当前位置: 首页 > news >正文

C++函数在库中的地址

本文讲述C++如何直接调用动态库dll或者so中的函数。

首先我们准备一个被调用库,这个库里面有两个函数,分别是C++98 与 C++11 下的,名称是run2和run1。

被调用库

相关介绍请看之前的文章《函数指针与库之间的通信讲解》。

//dll_ex_im.h
#ifndef __DLL_EX_IM_H__
#define __DLL_EX_IM_H__
#include <functional>
#include <string>
#include <iostream>
#include <thread>
#include <chrono>
#ifdef _WINDOWS
#ifdef DLLProvider
#define DLL_EXPORT_IMPORT		 __declspec(dllexport)  
#else  
#define DLL_EXPORT_IMPORT		 __declspec(dllimport)  
#endif  
#else
#define DLL_EXPORT_IMPORT __attribute__((visibility("default")))
#endif//typedef class DLL_EXPORT_IMPORT std::function< void(std::string)> output_to_caller;
DLL_EXPORT_IMPORT void run1(int a, std::function< void(std::string)> output);
DLL_EXPORT_IMPORT void run2(int a, void(*output)(std::string));#endif //__DLL_EX_IM_H__
//dll_ex_im.cpp
#include "dll_ex_im.h"void run1(int a, std::function< void(std::string)> output)
{std::cout << "run1" << std::endl;std::cout << "got parametrer: " << a << std::endl;std::cout << "return signal: " << std::endl;while (true) {output("run1: " + std::to_string(a++));std::this_thread::sleep_for(std::chrono::milliseconds(1000));}
}void run2(int a, void(*output)(std::string)) {std::cout << "run2" << std::endl;std::cout << "got parametrer: " << a << std:bian

编译一下,出来的动态库在Windows下是Reflection-DLL_TEST.dll,在Linux下是libReflection-DLL_TEST.so。

Windows下直接调用

我们用BinaryViewer这款二进制查看器看看函数run1和run2在Reflection-DLL_TEST.dll长什么样子。

查找函数run1的位置:

找到三个位置,前两个应该都是函数的名称指引(知道的同学可以介绍下前两个是做啥的)。
第三个是run1函数的地址:
在这里插入图片描述
我把这个run1地址写下来:

?run1@@YAXHV?$function@$$A6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@std@@@Z

原来的函数run1长这样:

void run1(int a, std::function< void(std::string)> output);

查找函数run2的位置:

找到三个位置,前两个应该都是函数的名称指引(知道的同学可以介绍下前两个是做啥的)。
第三个是run2函数的地址:
在这里插入图片描述
我把这个run2地址写下来:

?run2@@YAXHP6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@Z

原来的函数run2长这样:

void run2(int a, void(*output)(std::string));

地址解释

以上run1和run2函数在dll二进制文件中的地址是一个经过VS C++编译器名称修饰后的函数名,这种修饰是编译器用来区分具有相同名称但不同参数或返回类型的函数的方法。
由于我不是做编译器的,下面我用聊天机器人查了一下,仅给出以上run1函数地址的解释:
?run1@@:这是函数名run1的开头部分,其中?和@@是Microsoft编译器特有的名称修饰符号。
YAXH:这表示函数的返回类型和参数类型。在这个例子中,Y 表示返回类型为 void,AX 通常表示没有通过值传递的参数(但在这个特定情况下,由于后面有V,它实际上表示有一个通过引用或指针传递的参数),H 是参数列表的开始。不过,这里的AX和H的具体含义可能因编译器的具体实现而略有不同,重要的是理解整体结构。
V:这表示接下来的部分是一个通过引用或指针传递的参数。
?$function@…@std@@:这是对 std::function 模板的修饰表示,其中省略号(…)代表模板参数的具体类型,即 void(std::string)。
KaTeX parse error: Can't use function '$' in math mode at position 7: A6AXV?$̲basic_string@..…A6 是与调用约定相关的(可能是 __cdecl 的某种变体,但具体取决于编译器和平台),AXV 表示函数接受一个参数(V 表示通过引用或指针),?$basic_string@…@std@@@Z 是对 std::string 类型的修饰表示。

Windows调用程序

#include <iostream>
//#include <list>
#include <functional>
#ifdef _WINDOWS 
#include <shlwapi.h>
#include <Psapi.h> 
#include <codecvt> 
#else
#include <dlfcn.h>
#include <codecvt>
#endifvoid callback(std::string info) {std::cout << info << std::endl;
}void Run1(const std::string& dllpath, const std::string& initFuncName)
{std::string funName = initFuncName;
#ifdef _WINDOWStypedef void(_stdcall* pfnInitPlugin) (int, std::function< void(std::string)>);funName = "?" + funName + "@@YAXHV?$function@$$A6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@std@@@Z";auto module = LoadLibrary(dllpath.c_str());//寻找初始化函数,并执行pfnInitPlugin initfunc = (pfnInitPlugin)GetProcAddress(module, funName.c_str());if (initfunc){//常规方式//std::function< void(std::string)> cb = callback;//initfunc(4, cb);//lambda方式initfunc(4, [](std::string info) {std::cout << info << std::endl; });}else {std::cout << "未找到函数地址" << std::endl;}
#elsetypedef  void(__attribute__((__stdcall__))* pfnInitPlugin) (int, std::function< void(std::string));funName = "_Z22" + funName + "v";auto dp = dlopen(p.c_str(), RTLD_LAZY | RTLD_GLOBAL);if (dp){pfnInitPlugin initfunc = (pfnInitPlugin)dlsym(dp, funName.c_str());if (initfunc){initfunc(4, [](std::string info) {std::cout << info << std::endl;});}//dlclose(dp);}else {std::cout << "未找到函数地址" << std::endl;}
#endif
}void Run2(const std::string& dllpath, const std::string& initFuncName)
{std::string funName = initFuncName;
#ifdef _WINDOWStypedef void(_stdcall* pfnInitPlugin) (int, void(*output)(std::string));//run1funName = "?" + funName + "@@YAXHP6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@Z";auto module = LoadLibrary(dllpath.c_str());//寻找初始化函数,并执行pfnInitPlugin initfunc = (pfnInitPlugin)GetProcAddress(module, funName.c_str());if (initfunc){//void(*cb)(std::string);//cb = callback;//initfunc(4, cb);initfunc(4, [](std::string info) {std::cout << info << std::endl;});}else {std::cout << "未找到函数地址" << std::endl;}
#elsetypedef  void(__attribute__((__stdcall__))* pfnInitPlugin) (int, void(*output)(std::string));funName = "_Z22" + funName + "v";auto dp = dlopen(p.c_str(), RTLD_LAZY | RTLD_GLOBAL);if (dp){pfnInitPlugin initfunc = (pfnInitPlugin)dlsym(dp, funName.c_str());if (initfunc){initfunc(4, [](std::string info) {std::cout << info << std::endl;});}//dlclose(dp);}else {std::cout << "未找到函数地址" << std::endl;}
#endif
}int main(int argc, char* argv[]) {std::string argv1 = argv[1];if (argc == 2 && argv1 == "-h"){std::cout << "用法:\n【exe-name】【dll-path】【func-name】" << std::endl;return 0;}if (argc != 3){std::cerr << "传入的参数数量不对,应该是俩,检查检查!!" << std::endl;return -1;}std::string dllPath = argv[1];if (dllPath.find(".dll") == dllPath.npos){std::cerr << "传入的文件没有dll,检查检查!!" << std::endl;return -1;}std::string argv2 = argv[2];if (argv2 == "run1"){Run1(argv[1], "run1");}else if (argv2 == "run2") {Run2(argv[1], "run2");}else {std::cerr << "传入的函数名既不是 run1 也不是 run2 ,检查检查!!" << std::endl;return -1;}return 0;
}

在Windows下,核心代码是下面这几句:

	typedef void(_stdcall* pfnInitPlugin) (int, std::function< void(std::string)>);//run1funName = "?" + funName + "@@YAXHV?$function@$$A6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@std@@@Z";auto module = LoadLibrary(dllpath.c_str());//寻找初始化函数,并执行pfnInitPlugin initfunc = (pfnInitPlugin)GetProcAddress(module, funName.c_str());if (initfunc){//常规方式//std::function< void(std::string)> cb = callback;//initfunc(4, cb);//lambda方式initfunc(4, [](std::string info) {std::cout << info << std::endl; });}else {std::cout << "未找到函数地址" << std::endl;}

程序读入动态库,通过函数在动态库中的地址进行直接调用。
下面是调用结果:
在这里插入图片描述

Linux下直接调用

我们用BinaryViewer这款二进制查看器看看函数run1和run2在libReflection-DLL_TEST.so长什么样子。

查找函数run1的位置:

找到4个位置,前两个应该都是函数的名称指引(知道的同学可以介绍下前3个是做啥的)。
第4个是run1函数的地址:
在这里插入图片描述
我把这个run1地址写下来:

_Z4run1iSt8functionIFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE

原来的函数run1长这样:

void run1(int a, std::function< void(std::string)> output);

查找函数run2的位置:

找到4个位置,前两个应该都是函数的名称指引(知道的同学可以介绍下前3个是做啥的)。
第4个是run2函数的地址:
在这里插入图片描述
我把这个run2地址写下来:

_Z4run2iPFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE

原来的函数run2长这样:

void run2(int a, void(*output)(std::string));

地址解释

以上run1和run2函数在so二进制文件中的地址是一个由 GCC编译器生成的 mangled(修饰)名称。这种名称用于在编译后的代码中唯一标识函数、变量等符号,同时包含类型信息。Mangled 名称对于人类来说通常是不直观的,但它们对于编译器和链接器来说是必要的,以确保在复杂的程序中正确地解析和链接符号。
由于我不是做编译器的,下面我用聊天机器人查了一下,仅给出以上run1函数地址的解释:
_Z 前缀是 GCC 编译器用于 mangled 名称的标识。
4run1i 部分是函数名称的编码,其中 run 是函数名,1 表示该函数接受一个参数,i 表示该参数的类型(在这个上下文中,它实际上是指接下来的类型信息,而不是直接的类型)。
St8functionIFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE 是参数类型的 mangled 表示。这个类型是一个 std::function,它包装了一个可调用对象,该对象接受一个 std::string 类型的参数(没有返回值,因为 Fv 表示一个函数类型,没有返回类型)。
St8function 表示 std::function。
IFv 表示一个函数(F)没有返回值(v,即 void),并且接下来是参数类型。
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 是 std::__cxx11::basic_string<char, std::char_traits, std::allocator> 的 mangled 表示,即 std::string。

Linux调用程序

#include <iostream>
//#include <list>
#include <functional>
#ifdef _WINDOWS 
#include <shlwapi.h>
#include <Psapi.h> 
#include <codecvt> 
#else
#include <dlfcn.h>
#include <codecvt>
#endifvoid callback(std::string info) {std::cout << info << std::endl;
}void Run1(const std::string& dllpath, const std::string& initFuncName)
{std::string funName = initFuncName;
#ifdef _WINDOWStypedef void(_stdcall* pfnInitPlugin) (int, std::function< void(std::string)>);funName = "?" + funName + "@@YAXHV?$function@$$A6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@std@@@Z";auto module = LoadLibrary(dllpath.c_str());//寻找初始化函数,并执行pfnInitPlugin initfunc = (pfnInitPlugin)GetProcAddress(module, funName.c_str());if (initfunc){//常规方式//std::function< void(std::string)> cb = callback;//initfunc(4, cb);//lambda方式initfunc(4, [](std::string info) {std::cout << info << std::endl; });}else{std::cout<<"not find function name"<<std::endl;}
#elsetypedef  void(* pfnInitPlugin) (int, std::function< void(std::string)>);funName = "_Z4" + funName + "iSt8functionIFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE";auto dp = dlopen(dllpath.c_str(), RTLD_LAZY | RTLD_GLOBAL);if (dp){pfnInitPlugin initfunc = (pfnInitPlugin)dlsym(dp, funName.c_str());if (initfunc){initfunc(4, [](std::string info) {std::cout << info << std::endl;});}dlclose(dp);}else{std::cout<<"not find function name"<<std::endl;}
#endif
}void Run2(const std::string& dllpath, const std::string& initFuncName)
{std::string funName = initFuncName;
#ifdef _WINDOWStypedef void(_stdcall* pfnInitPlugin) (int, void(*output)(std::string));funName = "?" + funName + "@@YAXHP6AXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@Z";auto module = LoadLibrary(dllpath.c_str());//寻找初始化函数,并执行pfnInitPlugin initfunc = (pfnInitPlugin)GetProcAddress(module, funName.c_str());if (initfunc){//常规方式//void(*cb)(std::string);//cb = callback;//initfunc(4, cb);//lambda方式initfunc(4, [](std::string info) {std::cout << info << std::endl;});}else{std::cout<<"not find function name"<<std::endl;}
#elsetypedef  void(* pfnInitPlugin) (int, void(*output)(std::string));funName = "_Z4" + funName + "iPFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE";auto dp = dlopen(dllpath.c_str(), RTLD_LAZY | RTLD_GLOBAL);if (dp){pfnInitPlugin initfunc = (pfnInitPlugin)dlsym(dp, funName.c_str());if (initfunc){initfunc(4, [](std::string info) {std::cout << info << std::endl;});}dlclose(dp);}else{std::cout<<"not find function name"<<std::endl;}
#endif
}int main(int argc, char* argv[]) {//C++ 98//Lambda回调函数//Run1("./Reflection-DLL_TEST.dll","run1");std::string argv1 = argv[1];if (argc == 2 && argv1 == "-h"){std::cout << "用法:\n【exe-name】【dll-path】【func-name】" << std::endl;return 0;}if (argc != 3){std::cerr << "传入的参数数量不对,应该是俩,检查检查!!" << std::endl;return -1;}std::string dllPath = argv[1];if (dllPath.find(".so") == dllPath.npos){std::cerr << "传入的文件没有so,检查检查!!" << std::endl;return -1;}std::string argv2 = argv[2];if (argv2 == "run1"){Run1(argv[1], "run1");}else if (argv2 == "run2") {Run2(argv[1], "run2");}else {std::cerr << "传入的函数名既不是 run1 也不是 run2 ,检查检查!!" << std::endl;return -1;}//system("pause");return 0;
}

在Linux下,核心代码是下面这几句:

	typedef  void(* pfnInitPlugin) (int, std::function< void(std::string)>);funName = "_Z4" + funName + "iSt8functionIFvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE";auto dp = dlopen(dllpath.c_str(), RTLD_LAZY | RTLD_GLOBAL);if (dp){pfnInitPlugin initfunc = (pfnInitPlugin)dlsym(dp, funName.c_str());if (initfunc){initfunc(4, [](std::string info) {std::cout << info << std::endl;});}dlclose(dp);}else{std::cout<<"not find function name"<<std::endl;}

程序读入动态库,通过函数在动态库中的地址进行直接调用。
下面是调用结果:
在这里插入图片描述

相关文章:

C++函数在库中的地址

本文讲述C如何直接调用动态库dll或者so中的函数。 首先我们准备一个被调用库&#xff0c;这个库里面有两个函数&#xff0c;分别是C98 与 C11 下的&#xff0c;名称是run2和run1。 被调用库 相关介绍请看之前的文章《函数指针与库之间的通信讲解》。 //dll_ex_im.h #ifndef…...

图像生成大模型imagen

要生成图像&#xff0c;可以使用深度学习模型&#xff0c;比如 OpenAI 的 DALLE、Google 的 Imagen 等。由于这些模型通常需要较大的计算资源和训练数据&#xff0c;下面是一些如何使用这些模型的基本步骤和方法。 使用预训练图像生成模型 选择模型&#xff1a; 常用的模型包括…...

Redis集群知识及实战

1. 为什么使用集群 在哨兵模式中&#xff0c;仍然只有一个Master节点。当并发写请求较大时&#xff0c;哨兵模式并不能缓解写压力。我们知道只有主节点才具有写能力&#xff0c;那如果在一个集群中&#xff0c;能够配置多个主节点&#xff0c;是不是就可以缓解写压力了呢&…...

数据报表轻松管理,强大“后台”不可少

在数据驱动的时代&#xff0c;制作一份高效、精准的数据报表成为企业管理和决策的重要手段。但要做好数据报表&#xff0c;不仅需要一款功能强大的报表工具&#xff0c;还必须有一个强有力的“后台”管理系统来支撑。那么&#xff0c;为什么报表工具需要一个管理后台&#xff1…...

简易CPU设计入门:本CPU项目的指令格式

在这一节里面&#xff0c;主要是理论知识&#xff0c;基本上不讲代码。不过&#xff0c;本项目的代码包&#xff0c;大家还是需要下载的。 本项目的代码包的下载方法&#xff0c;参考下面的链接所指示的文章。 下载本项目代码 本节&#xff0c;其实是要讲本项目CPU的指令集。…...

Datawhile 组队学习Tiny-universe Task01

Task01&#xff1a;LLama3模型讲解 仓库链接&#xff1a;GitHub - datawhalechina/tiny-universe: 《大模型白盒子构建指南》&#xff1a;一个全手搓的Tiny-Universe 参考博客&#xff1a;LLaMA的解读与其微调(含LLaMA 2)&#xff1a;Alpaca-LoRA/Vicuna/BELLE/中文LLaMA/姜子…...

MCU与SOC的区别

自动驾驶中 MCU 与 SoC 的区别 在自动驾驶系统中&#xff0c;**MCU&#xff08;微控制单元&#xff0c;Microcontroller Unit&#xff09;和SoC&#xff08;系统级芯片&#xff0c;System on Chip&#xff09;**都是关键的电子元件&#xff0c;但它们在性能、功能和应用领域等…...

51单片机-DS18B20(温度传感器)AT24C02(存储芯片) IIC通信-实验2-温度实时监测(可设置阈值)

作者&#xff1a;王开心 座右铭&#xff1a;刻苦专研&#xff0c;百折不挠&#xff0c;千磨万击还坚韧&#xff0c;任尔东西南北风&#xff01;干就完了&#xff01;&#xff08;可交流技术&#xff09; 主要利用DS18B20芯片去采集温度&#xff0c;通过采集的温度能够自动保存…...

Vue2接入高德地图API实现搜索定位和点击获取经纬度及地址功能

目录 一、申请密钥 二、安装element-ui 三、安装高德地图依赖 四、完整代码 五、运行截图 一、申请密钥 登录高德开放平台&#xff0c;点击我的应用&#xff0c;先添加新应用&#xff0c;然后再添加Key。 如图所示填写对应的信息&#xff0c;系统就会自动生成。 二、安装…...

msvcp140.dll丢失如何解决?msvcp140.dll丢失的多种解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”。这个错误通常会导致某些应用程序无法正常运行&#xff0c;给用户带来很大的困扰。那么&#xff0c;当我们遇到msvcp140.dll丢失的情况时&#xff0c;应该如何解决呢&a…...

高效财税自动化软件如何提升企业财务工作的效率与准确性

在当今企业运营中&#xff0c;财务管理发挥着核心作用。它不仅涉及企业正常运转和市场决策&#xff0c;还是推动企业向高质量发展迈进的关键动力。面对激烈的市场竞争与科技革新的双重挑战&#xff0c;财务管理亟需进行持续的转型与提升&#xff0c;为企业高质量发展目标的实现…...

Leetcode 3286. Find a Safe Walk Through a Grid

Leetcode 3286. Find a Safe Walk Through a Grid 1. 解题思路2. 代码实现 题目链接&#xff1a;3286. Find a Safe Walk Through a Grid 1. 解题思路 这一题的话思路上就是一个宽度优先遍历&#xff0c;我们按照health进行排序进行宽度优先遍历&#xff0c;看看在health被消…...

shell脚本语法

shell脚本的变量 系统变量 系统变量是操作系统用来存储配置信息的变量&#xff0c;它们可以控制操作系统的行为和程序的运行环境。系统变量的种类和内容取决于操作系统的类型和版本。以下是一些常见的系统变量类别和它们可能包含的内容&#xff1a; 环境变量&#xff1a;这些…...

TCP 拥塞控制:一场网络数据的交通故事

从前有条“高速公路”&#xff0c;我们叫它互联网&#xff0c;而这条公路上的车辆&#xff0c;则是数据包。你可以把 TCP&#xff08;传输控制协议&#xff09;想象成一位交通警察&#xff0c;负责管理这些车辆的行驶速度&#xff0c;以防止交通堵塞——也就是网络拥塞。 第一…...

(黑马点评) 五、探店达人系列功能实现

5.1 发布和查看探店笔记 5.1.1 发布探店笔记 这块代码黑马已经完成了&#xff0c;在发布探店笔记界面&#xff0c;有两块内容是需要上传的。一是笔记内容&#xff0c;二是笔记配图。其中笔记配图部分黑马使用的是上传到本地前端服务器上面的。我我觉得可以将图片文件发布在阿里…...

SQLiteDatabase insert or replace数据不生效

在Android开发中&#xff0c;如果您在SQLite数据库中更新了数据&#xff0c;但重启应用后更新的数据不再生效&#xff0c;那么可能的原因有&#xff1a; 更新操作没有正确执行&#xff0c;可能是由于SQL语句错误或者数据库没有正确打开。 更新操作在事务中没有被正确提交。 更…...

基于Python实现一个浪漫烟花秀

为了实现一个类似烟花秀的效果&#xff0c;我们可以通过复杂的粒子系统来模拟烟花的升起、绽放和下落效果。以下是一个示例&#xff0c;旨在创建更为动态和逼真的烟花秀效果。 示例代码 这个代码示例将使用 matplotlib 和 numpy&#xff0c;并实现更丰富的视觉效果&#xff1…...

电气自动化入门03:安全用电

视频链接&#xff1a;2.1 电工知识&#xff1a;触电原因与防触电措施_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1PJ41117PW/?p4&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.电流对人体的危害 电击&#xff1a;电流通过人体。 电伤&#xff1a;电流热效应…...

【深度学习】(2)--PyTorch框架认识

文章目录 PyTorch框架认识1. Tensor张量定义与特性创建方式 2. 下载数据集下载测试展现下载内容 3. 创建DataLoader&#xff08;数据加载器&#xff09;4. 选择处理器5. 神经网络模型构建模型 6. 训练数据训练集数据测试集数据 7. 提高模型学习率 总结 PyTorch框架认识 PyTorc…...

前端面试记录

js 1. 函数式编程 将计算过程视为一系列的函数调用,函数的输出完全由输入决定&#xff0c;不依赖于或改变程序的状态,使得函数式编程的代码更加可预测和易于理解。 函数式编程的三个核心概念&#xff1a;纯函数、高阶函数和柯里化。 高阶函数&#xff1a;函数可以作为参数传…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...