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

电商平台网站开发过程百度做网站的费用

电商平台网站开发过程,百度做网站的费用,方维服务客户类型,模仿网站建设静态链接与动态链接 静态链接 静态链接是指在程序编译阶段,将所有需要的库代码直接复制到最终生成的可执行文件中,形成一个整体,运行时不再依赖外部库文件。 静态链接就像是把所有用到的工具都打包进了你的应用程序里。不管用到的库有多大…

静态链接与动态链接

静态链接

静态链接是指在程序编译阶段,将所有需要的库代码直接复制到最终生成的可执行文件中,形成一个整体,运行时不再依赖外部库文件。

静态链接就像是把所有用到的工具都打包进了你的应用程序里。不管用到的库有多大,最终生成的可执行文件(比如 a.out)都会把这些库内容直接塞进去。运行的时候,这个程序是“自给自足”的,不依赖外面的库文件,哪怕系统上删掉了原本的库,它也能跑。

动态链接

动态链接是指在程序运行时,按需加载外部共享库(Shared Libraries),程序本身只包含对库函数的引用,不包含库代码,运行时由操作系统动态地链接这些库。

动态链接就像是你写了个程序,但工具箱没直接塞到程序里,而是告诉程序到时候用外面的现成工具箱。程序里只是记了下:“要用 xxx 工具箱,到时候系统帮我找来”。运行时,操作系统发现你程序里要用 libm.so(数学库),就把 /usr/lib/ 里的 libm.so 给你挂上去。

动态链接的好处

  • 节省磁盘空间
    多个程序共享同一个库文件,不需要每个程序各拷一份。

  • 节省内存
    操作系统可以让多个程序共享加载到内存中的同一个库副本(比如共享只读段)。

  • 便于维护和升级
    修复一个库的 bug、安全漏洞,只要替换库文件,不需要修改和重新编译依赖它的所有程序。

  • 支持插件和模块化设计
    可以根据需要在运行时加载特定模块(比如浏览器动态加载视频插件)。

  • 提升程序灵活性
    程序可以根据实际情况决定加载哪个版本的库,甚至可以在运行时切换不同功能。

libdl.so 和 <dlfcn.h> 简介

libdl.so

libdl.so 是一个专门用于支持运行时动态链接(dynamic linking)的标准共享库,提供了在程序运行过程中加载、使用和卸载其他共享对象(.so文件)的接口。

libdl.so 就是一个专门管理“动态加载库”的小管家库。程序运行到一半的时候,如果需要额外功能(比如一个新的模块),就可以通过调用 libdl.so 里的功能,把外面的 .so 文件(共享库)搬进来用。简单理解,libdl.so 提供了“程序自己动手,运行时找库、开箱、拿函数用”的能力。

<dlfcn.h>

<dlfcn.h> 是一个标准头文件,定义了操作运行时共享对象(dynamic shared objects,DSO)所需的接口函数、数据类型和错误处理机制。

<dlfcn.h> 就是声明了那些能让你“打开.so文件、找符号、关闭库”的函数的地方。如果你想在程序里动态加载库,就必须先 #include <dlfcn.h>,否则编译器不知道你在说什么。

二者关系

libdl.so真正实现动态链接功能的共享库(里面是编译好的二进制代码)。

<dlfcn.h>提供 libdl.so 功能对应函数声明的头文件(让编译器知道你要调用哪些函数)。

一个是实打实干活的工具箱(libdl.so),
一个是告诉程序怎么用这个工具箱的说明书(dlfcn.h)。

<dlfcn.h> 提供的常用API

前置概念

共享库:是将某些功能或模块封装成一个独立的文件(.so 文件/.ddl文件)并供多个程序同时使用的技术。在 Linux 系统中,扩展名通常为 .so,在 Windows 系统中则为 .dll。比如在linux中自己实现了mymath.h、mymath.cpp,通过gcc/g++将其编译成了一个libmymath.so文件,这个文件就叫共享库。

共享库的符号:指共享库中的变量、函数、类等可提供外部程序使用的标识符,如mymath.h中实现的add(int x, int y)就称为共享库的符号

dlopen()

打开一个动态链接库文件并返回一个句柄,该句柄用于后续的操作,  如查找符号、关闭库等。

void* dlopen(const char* filename, int flag);

参数: 

filename:

  1. 1.指定动态库文件的路径,如果传入NULL表示打开的是调用进程的主程序(可以直接用来查找主程序中的符号:比如说我是在a.cpp文件中调用到dlopen并传入一个NULL,那得到的这个句柄中可以得到a.cpp中的符号)。
  2. 2.可以是相对路径或绝对路径。3.如果路径中不包含/,动态链接器会根据LD_LIBRARY_PATH环境变量搜索库文件。

flag:指定加载动态库的方式,可以通过|组合使用

返回值:

成功调用返回动态库的句柄,失败返回NULL,可通过dlerror获取错误信息

示例:

比如我们已经实现了mymath.h/.cpp并编译出一个Libmymath.so文件

void* handle = dlopen("./libmymath.so", RTLD_LAZY);
if (!handle) {std::cerr << "Failed to open library: " << dlerror() << std::endl;
}

dlsym()

在打开的动态库中查找指定的符号(函数、变量),并返回符号的地址。

void* dlsym(void* handle, const char* symbol);

参数:

handle:动态库的句柄,由dlopen返回。如果传入宏RTLD_DEFAULT,表示在全局符号表中查找符号。如果传入宏RTLD_NEXT,表示从当前共享库之后加载(如果我使用dlopen libb.so得到的句柄handleB去调用dlsym时,并且在dlopen libb.so之前,我dlopen了liba.so,在dlopen libb.so之后,我dlopen了libc.so,那么如果给handleB传一个RTLD_NEXT时,会在libc.so中去查找)。

symbol:要查找的符号名称(通常是函数名或变量名),大小写敏感

返回值:

成功调用返回符号的地址,调用失败返回NULL,可通过dlerror获取错误信息

示例:

假如mymath.h中有个方法叫add

typedef int (*AddFunc)(int, int);   // 定义函数指针类型// 查找符号 add
AddFunc add = (AddFunc)dlsym(handle, "add");
const char* dlsym_error = dlerror();
if (dlsym_error) {std::cerr << "Cannot load symbol 'add': " << dlsym_error << std::endl;dlclose(handle);
}

dlclose()

关闭先前打开的动态链接库。

int dlclose(void* handle);

参数:

handle:动态库的句柄,由dlopen返回

返回值

失败返回非0值。

如果关闭一个库时还有其他库正在使用该库的符号,库不会立即卸载,而是等待符号的引用计数降为0时卸载。在dlopen时使用RTLD_NODELETE宏时,调用dlclose后不会真正卸载。

dlerror()

返回最近一次动态链接库操作的错误信息。

const  char* dlerror();

返回值:

成功返回NULL表示无错误,失败返错误信息的字符串。

每次调用dlerror都会清楚之前的错误状态。

<dlfcn.h>使用示例

使用动态库加载一个日志模块

logger.h/logger.cpp的实现

// logger.h
#pragma once
#include <string>extern "C" {    //用了 extern "C",防止 C++ 函数名被编译器改名(名字修饰/mangling),这样 dlsym 能直接找字符串 "initLogger" 等。// 初始化日志系统
void initLogger(const char* filename);// 写一条 info 级别的日志
void logInfo(const char* message);// 关闭日志系统
void closeLogger();}// logger.cpp
#include "logger.h"
#include <fstream>static std::ofstream logFile;void initLogger(const char* filename) {logFile.open(filename, std::ios::app);if (logFile.is_open()) {logFile << "[Logger] Initialized.\n";}
}void logInfo(const char* message) {if (logFile.is_open()) {logFile << "[INFO]: " << message << "\n";}
}void closeLogger() {if (logFile.is_open()) {logFile << "[Logger] Closed.\n";logFile.close();}
}

 编译成共享库liblogger.so

g++ -fPIC -shared -o liblogger.so logger.cpp

main 

#include <iostream>
#include <dlfcn.h>    // 引入动态链接相关APItypedef void (*InitLoggerFunc)(const char*);
typedef void (*LogInfoFunc)(const char*);
typedef void (*CloseLoggerFunc)();int main() {// 打开动态库void* handle = dlopen("./liblogger.so", RTLD_LAZY);if (!handle) {std::cerr << "Error opening library: " << dlerror() << std::endl;return 1;}// 清除之前的错误dlerror();// 查找 initLoggerInitLoggerFunc initLogger = (InitLoggerFunc)dlsym(handle, "initLogger");const char* error1 = dlerror();if (error1) {std::cerr << "Error loading symbol 'initLogger': " << error1 << std::endl;dlclose(handle);return 1;}// 查找 logInfoLogInfoFunc logInfo = (LogInfoFunc)dlsym(handle, "logInfo");const char* error2 = dlerror();if (error2) {std::cerr << "Error loading symbol 'logInfo': " << error2 << std::endl;dlclose(handle);return 1;}// 查找 closeLoggerCloseLoggerFunc closeLogger = (CloseLoggerFunc)dlsym(handle, "closeLogger");const char* error3 = dlerror();if (error3) {std::cerr << "Error loading symbol 'closeLogger': " << error3 << std::endl;dlclose(handle);return 1;}// 使用动态库的功能initLogger("app.log");logInfo("Program started.");logInfo("Doing something important...");closeLogger();// 关闭动态库dlclose(handle);return 0;
}

dlfcn.h中的常用宏

RTLD_LAZY、RTLD_NOW:

是dlopen的可选参数,分别表示懒加载和立即加载动态链接库中的符号。

RTLD_GLOBAL、RTLD_LOCAL:

是dlopen的可选参数分别表示符号的全局可见性和局部可见性。

这些函数和宏可以用于在运行时加载和卸载动态链接库,动态链接库的使用使得程序可以在运行时动态的加载和调用函数,从而使得程序的可扩展性更强。

RTLD_LAZY:懒加载

当使用懒加载打开一个共享库(如.so文件)时,动态连接器会采用一种懒加载的方式,即只在你第一次实际使用某个函数或变量时(通过dlsym得到的符号被实际使用时)才去解析他(解析时只会解析该符号并与之相关的符号,其他符号不参与解析)。而不是在一开始就解析动态库中的所有符号(函数或变量)。就像一本字典,只有当你查某个单词时才去翻找某个单次,而不是一开始就把正本字典读一遍。

  1. 优点:启动更快、更节省资源
  2. 缺点:潜在问题暴露的更晚(只有等到用到这些符号是才会报错)
  3. void* handle = dlopen("./liblazytest.so", RTLD_LAZY);

RTLD_NOW:立即加载

当使用立即加载加载一个共享库时,动态连接器会立即解析共享库中的所有符号(函数和变量),并把它们帮绑定到程序中。他和懒加载不同,他是一种立即绑定的方式。就像一本字典,会立即查找所有单次的意思,并把它们写在笔记本上备用。在调用dlopen时,动态链接器会把共享库里所有的函数、变量都加载好,并检查他们是否有问题,如果某个符号有问题,程序会在启动时直接报错,而不是运行到那个地方才报错。

  1. 优点:更可靠,如果共享库有问题,可以马上发现问题
  2. 缺点:启动变慢,因为在启动时要解析所有符号
void* handle = dlopen("./liblazytest.so", RTLD_NOW);

RTLD_GLOBAL:全局加载

当在dlopen时使用了全局加载这个宏后,加载的共享库里的符号(函数或变量)会被放到一个全局符号表里,这样后续加载的其他共享库也可以直接解析使用这些符号,而不需要重新定义或加载他们。默认情况没有使用RTLD_GLOBAL时,如果使用dlopen加载一个共享库,这个库里的符号(比如函数名)只能被当前加载的这个库本身使用,其他共享库不能直接访问它。如果使用了RTLD_GLOBAL这个共享库会被公开,放到全局符号表里。这样后面加载的其他共享库可以直接使用这些符号,就像他们是公共资源一样。

示例:
如果libB.so中某个函数间接使用了libA.so中的符号,如果我们不使用RTLD_GLOBAL的话,直接通过dlopen打开libB.so动态链接库得到句柄handleB,然后通过dlsym,在handleB中查找某个函数(这个符号包括libA.so中的符号),虽然能正常查到这个函数,但调用这个函数时会报错,所以我们需要先通过dlopen打开libA.so并使用RTLD_GLOBAL宏,然后在使用handleB去查询该函数,此时不会报错。注意:在这种情况下,只有需要被共享的库libA.so需要在dlopen时使用RTLD_GLOBAL。

a.h  b.h

a.h
#pragma once
void hello_from_A();a.cpp
#include <iostream>
#include "a.h"
void hello_from_A() {std::cout << "Hello from libA.so!" << std::endl;
}b.h
#pragma once
void call_hello_from_A();
b.cpp
#include "a.h"
#include "b.h"
void call_hello_from_A() {hello_from_A(); // 调用 libA.so 中的函数
}

编译  libA.sp  libB.so

g++ -fPIC -shared a.cpp -o libA.sog++ -fPIC -shared b.cpp -o libB.so -L. -lA

main

#include <iostream>
#include <dlfcn.h>typedef void (*CallHelloFunc)();int main() {// 第一步:加载 libA.so,使用 RTLD_GLOBALvoid* handleA = dlopen("./libA.so", RTLD_LAZY | RTLD_GLOBAL);if (!handleA) {std::cerr << "Failed to open libA.so: " << dlerror() << std::endl;return -1;}std::cout << "libA.so loaded with RTLD_GLOBAL." << std::endl;// 第二步:加载 libB.sovoid* handleB = dlopen("./libB.so", RTLD_LAZY);if (!handleB) {std::cerr << "Failed to open libB.so: " << dlerror() << std::endl;return -1;}std::cout << "libB.so loaded." << std::endl;// 第三步:查找 call_hello_from_A 函数CallHelloFunc callHello = (CallHelloFunc)dlsym(handleB, "call_hello_from_A");if (!callHello) {std::cerr << "Failed to find call_hello_from_A: " << dlerror() << std::endl;return -1;}// 第四步:调用callHello();// 关闭dlclose(handleB);dlclose(handleA);return 0;
}

正常输出

libA.so loaded with RTLD_GLOBAL.
libB.so loaded.
Hello from libA.so!

 但是如果不在加载 libA.so 时加 RTLD_GLOBAL(比如只写 RTLD_LAZY)

void* handleA = dlopen("./libA.so", RTLD_LAZY); // 去掉 RTLD_GLOBAL

重新编译后运行,结果会是

  • dlsym 查询 call_hello_from_A 成功

  • 但在 callHello() 调用时,程序崩溃或者出现类似下面这种错误

undefined symbol: hello_from_A

原因就是libB.so 里的 call_hello_from_A() 需要用 hello_from_A(),但是因为 libA.so 的符号没有公开到全局符号表,libB.so 找不到

RTLD_LOCAL:本地加载/局部加载

在没有使用RTLD_GLOBAL宏时,它是默认使用的宏。它用来限制动态库的符号范围。使用RTLD_LOCAL加载的动态库,其内部的函数或变量(符号),不会被放入全局符号表,其他动态库无法访问这些符号。当多个动态库中有同名符号是可以避免不必要的冲突或覆盖。如果动态库只需要自身使用,不希望其他库依赖他的符号时,可以使用RTLD_LOCAL.


文章转载自:

http://RV0rHcuW.jghqc.cn
http://CARr4qo5.jghqc.cn
http://sfJGV9Rt.jghqc.cn
http://RKcxlhml.jghqc.cn
http://Lzgq7drD.jghqc.cn
http://Mkcz0tOL.jghqc.cn
http://ZiwC8uwy.jghqc.cn
http://1uRhghVb.jghqc.cn
http://6utX4APb.jghqc.cn
http://2aiPgEc2.jghqc.cn
http://WKGDuSF1.jghqc.cn
http://6ZinsxY2.jghqc.cn
http://4LEdFUnk.jghqc.cn
http://gBqgxGdj.jghqc.cn
http://VR78zUUm.jghqc.cn
http://I2Dg57nx.jghqc.cn
http://Y1UEmtcM.jghqc.cn
http://qCwObw7X.jghqc.cn
http://fbmKYcFY.jghqc.cn
http://8nKg6OZm.jghqc.cn
http://CrUWzWoO.jghqc.cn
http://KBWASfGQ.jghqc.cn
http://TlyfdmZl.jghqc.cn
http://vkRbvi5g.jghqc.cn
http://cfQVTpWi.jghqc.cn
http://UerbWdgu.jghqc.cn
http://uQG5jUcG.jghqc.cn
http://PHelfu79.jghqc.cn
http://OPlpb3nA.jghqc.cn
http://r0JKF4QA.jghqc.cn
http://www.dtcms.com/wzjs/641704.html

相关文章:

  • 网站后台怎么上传文件分分彩做号网站
  • 养生网站建设免费网站建设收费标准行情
  • 济南定制网站建设申请网站主机
  • 网站幻灯网站建设公司哪家比较好
  • 四会市城乡规划建设局网站沙田网站建设
  • 白云网站(建设信科网络)塘厦镇
  • 欧米伽官方网站手表价格企业网站优化的弊端
  • 网站建设以及推广提案书吴江区经济开发区规建设局网站
  • 营销推广型网站公司可以做音乐mv视频网站
  • 怎么键卖东西的网站wordpress中国最好主题
  • 公司做网站设计要注意网站开发工具 知乎
  • 如何在百度上做公司网站朝阳网站建设 高碑店
  • wordpress插件怎么破解网站seo 优化
  • 企业形象通用网站用路由器做简单的网站
  • 摄影网站的需求分析个人网站 外贸
  • 【转】网页 网站 html如何实现"关闭窗口"代码大全博物馆 网站 建设
  • 建设网站需要的配置为网站制定一个推广计划
  • 科技网站域名百度 wordpress react
  • 如何制作一个注册网站中企动力全球邮企业邮箱
  • 营销型企业网站建设步骤网站建站是模版好还是设计好
  • 显示网站建设中建筑设计方案网站
  • 写作网站哪个能得稿费少女免费观看完整电视电影
  • 好的html5网站模板中英语双语网站咋做
  • 哪个网站做课件ppt比较好wordpress 地图菜单
  • 网站如何吸引人品牌推广的目的和意义
  • 小型门户网站建设硬件配置南京一等一网络科技有限公司
  • c语言网络编程网站优化与seo的区别
  • 安徽合肥建设局网站做百度竞价用什么网站
  • 爱网站最新发布址动态电商网站怎么做
  • 培训机构一般在什么网站做推广网站统计系统