使用dlopen/dlsym加载C++共享库时dlsym返回NULL的问题
问题根源:C++的名字修饰(Name Mangling)
你遇到的dlsym返回NULL的核心原因是C++编译器会对函数名进行名字修饰,而你在C代码里尝试查找的是未修饰的原始函数名"nothing",两者不匹配。
从你提供的nm -D sym.so输出可以看到,实际导出的符号是_Z7nothingv,这是GCC对C函数nothing()进行名字修饰后的结果。C通过这种方式支持函数重载等特性,但这就导致C代码(比如你的symtest.c)无法直接通过原始函数名找到C++编译的函数。
解决方案:用extern "C"禁用名字修饰
修改你的sym.cpp,用extern "C"包裹函数的声明和定义,强制编译器按照C语言的规则生成符号名,避免名字修饰:
extern "C" int nothing(); extern "C" int nothing() { return 0; }
或者更简洁的写法:
extern "C" { int nothing() { return 0; } }
验证修改效果
重新编译共享库和测试程序:
$ g++ -shared -fPIC -o sym.so sym.cpp $ gcc symtest.c -ldl -o symtest $ ./symtest
这次运行后不会输出NULL,因为dlsym现在能找到正确的符号nothing。你也可以用nm -D sym.so再次验证,会看到导出的符号变成了:
0000000000000670 T nothing
关联Redis模块场景的解释
回到你提到的Redis模块问题:Redis是用C语言编写的,它会在加载模块时查找RedisModule_OnLoad这个C风格的符号。如果你的模块用C编写但没有用extern "C"导出该函数,C编译器会对它进行名字修饰,导致Redis找不到对应的符号,从而报错"does not export RedisModule_OnLoad() symbol"。解决方法也是一样的——用extern "C"包裹RedisModule_OnLoad的定义。
内容的提问来源于stack exchange,提问作者Sidd Singal
相关产品推荐
相关产品推荐

