两个知识点的回顾(const指针和动态链接库函数dlopen)
昨天,看了一点《c++ primer》和《程序员的自我修养》,想起了自己以前的两个知识点,这里回顾,并且总结一下。
1. const指针的参数
看primer的时候,看到几个概念,虽然都大概知道,但是还是有点模糊的,今天权且记在这里。
(1)const形参
const形参,从const的意思来看,就是形参是const的,不能够改变。但是函数在传值的时候都是传的副本,所以不管形参是不是const,都可以使用const或者非const的实参传递。【注:这里指的是普通的形参】
(2)const引用避免复制
这个是之前不理解的,在c++中,const的引用是不会发生复制行为的,这样在大类型为参数的时候,节省了复制的时间,提高了效率。
(3)非const的引用不灵活
因为形参是非const,这样导致传进来的的参数必须是非const,从而字符串常量已经const的参数就导致编译错误了。
(4)总结
看到这里的时候,想起以前面试的时候一道题:
char str1[] = "string";
char *str2 = "string";
testfunc1(char *str1)
testfunc2(const char*str),问下面表达式的对与错,
*testfunc1(str1)
*testfunc1(str2)
*testfunc2(str1)
*testfunc2(str2)
解释:
str1是一个字符数值,也可以理解为c风格的字符串(针对c++),大小为7,包括最后的'\0'。
str2是一个指向const类型的字符串的指针,大小也是7,不能修改了。
testfunc1的形参是一个非const的字符串指针
testfunc2的形参是一个指向const字符串的指针,在函数体能不能修改str的值。这只是表示不能在函数中对str修改。
所以从const的意义上,我给出的答案是
*testfunc1(str1) Y
*testfunc1(str2) N 函数体内是可以修改str2的,但是str2是const,不能被修改。
*testfunc2(str1) Y
*testfunc2(str2) Y
2. 动态链接库的接口函数使用
(1)书上代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | #include <stdio.h> #include <dlfcn.h> #define SETUP_STACK \ i = 2; \ while (++i < argc - 1) { \ printf ( "i: %d\n" , i);\ switch (argv[i][0]) { \ case 'i' : \ printf ( "%d\n" , i);\ asm volatile ( "push %0" :: \ "r" ( atoi (&argv[i][1])) ); \ esp += 4; \ printf ( "%d\n" , i);\ break ; \ case 'd' : \ atof (&argv[i][1]); \ asm volatile ( "subl $8, %esp\n" \ "fstpl (%esp)" ); \ esp += 8; \ break ; \ case 's' : \ asm volatile ( "push %0" :: \ "r" (&argv[i][1]) ); \ esp += 4; \ break ; \ default : \ printf ( "error argument type" ); \ goto exit_runso; \ } \ printf ( "%d\n" , i);\ } #define RESOTRE_STACK \ asm volatile ( "add %0, %%esp" :: "r" (esp)) int main( int argc, char * argv[]) { void *handle; char *error; int i; int esp = 0; void *func; handle = dlopen(argv[1], RTLD_NOW); if (0 == handle) { printf ( "Can't find library: %s\n" , argv[1]); return -1; } func = dlsym(handle, argv[2]); if ((error = dlerror()) != NULL) { printf ( "Find symbol %s error: %s\n" , argv[2], error); goto exit_runso; } switch (argv[argc - 1][0]) { case 'i' : { int (*func_int)() = func; SETUP_STACK; printf ( "%p\n" , func_int); int ret = func_int(); RESOTRE_STACK; printf ( "ret = %d\n" , ret); break ; } case 'd' : { double (*func_double)() = func; SETUP_STACK; double ret = func_double(); RESOTRE_STACK; printf ( "ret = %f\n" , ret); break ; } case 's' : { char * (*func_str)() = func; SETUP_STACK; char *ret = func_str(); RESOTRE_STACK; printf ( "ret = %s\n" , ret); break ; } case 'v' : { void (*func_void)() = func; SETUP_STACK; func_void(); RESOTRE_STACK; printf ( "ret = void" ); break ; } } /* end of switch */ exit_runso: dlclose(handle); } |
后面比较简单,前面的汇编代码没怎么看懂,再研究一下。
(2)回顾自己之前的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void prepare_start_dark(){ /* 调入动态函数分析 */ handle=dlopen( "./lxx.so" ,RTLD_LAZY); //open lib file if (handle == NULL){ printf( "Warning: no lib file, program go on!\n" ); daylog_error( "Warning: no lib file, program go on!\n" ); get_xx = get_xx_default; } else { get_xx = dlsym(handle, "get_xx" ); //call dlsym function } } void prepare_end_dark(){ /* */ if (handle != NULL) dlclose(handle); } |
感觉之前写的还是比较正常的,唯一不一样的是用了RTLD_LASY,应该是查资料的时候,别人这样用的,就直接copy过来的。看了书之后,知道是延迟绑定,就是动态链接器启动加载的时候并不是把所有的共享对象都加载进去,而是加载一部分需要的,这样提高了程序启动时候的性能。延迟绑定就是第一次用到的时候在加载!
(3)总结
还是有点为了学习而学习的感觉,上面的汇编代码一定要去学习看明白!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统