请教一个gcc生成函数名的问题

thenocturne 2005-12-30 12:01:09
请教各位达人一个问题:
unix下用gcc编译c程序时,动态库函数和静态库函数的生成函数名规则是一样的么?
如果不一样,那编译器怎么区别隐式声明的动态库函数和静态库函数的呢?
比如我用__stdcall声明了一个外部函数function,
gcc编译后的函数名是_function@n还是function@n呢?
...全文
859 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
thenocturne 2006-01-05
  • 打赏
  • 举报
回复
坦白一下,那个库是intel IPP的库 :P,
用nm看了一下那个库中一个函数ippsConvert_8s32f,输出如下:

$ nm ipps20.lib | grep _ippsMulC_32f_I
00000000 I __imp__ippsMulC_32f_I
00000000 T _ippsMulC_32f_I

相应头文件中函数的声明为:
extern "C" IppStatus __stdcall ippsMulC_32f_I(Ipp32f val, Ipp32f* pSrcDst, int len);
用g++编译,说:undefined reference to `ippsMulC_32f_I@12',看来gcc生成的函数名就是ippsMulC_32f_I@12。

我把函数声明改为:extern "C" IppStatus __cdecl _ippsMulC_32f_I(Ipp32f val, Ipp32f* pSrcDst, int len);将__stdcall改成了__cdecl,又在函数前面加了一个下划线_,用gcc编译,说:undefined reference to ‘_ippsMulC_32f_I'。这次和nm看到的函数应该一样了吧,还是报错,无语...

再将函数声明改为:extern "C" IppStatus __stdcall _ippsMulC_32f_I(Ipp32f val, Ipp32f* pSrcDst, int len)。编译,说:undefined reference to `_ippsMulC_32f_I@12',
我没辙了...
wfwater 2006-01-03
  • 打赏
  • 举报
回复
mark
x86 2005-12-31
  • 打赏
  • 举报
回复
确定那个第三方的头文件在mingw下可用么?如果不是,不妨去掉_stdcall看看.

另外ld也有一些参数可以研究一下,比如:
--kill-at可以去掉函数名@后面的部分,用gcc的-Wl参数将选项传给ld,像这样:
gcc -Wl,--kill-at -o test test.c

此外还有一些相关的选项:
--add-stdcall-alias Export symbols with and without @nn
--disable-stdcall-fixup Don't link _sym to _sym@nn
--enable-stdcall-fixup Link _sym to _sym@nn without warnings
-Bdynamic, -dy, -call_shared Link against shared libraries
-Bstatic, -dn, -non_shared, -static Do not link against shared libraries

实在不行给你出个主意, 不妨用VC再写个库去link那个第三方库, 做个简单封装, 你的gcc去link那个VC生成的库.
fierygnu 2005-12-31
  • 打赏
  • 举报
回复
原来这样。那楼主去看http://www.mingw.org/mingwfaq.shtml
How can an MSVC program call a MinGW DLL, and vice versa?
x86 2005-12-31
  • 打赏
  • 举报
回复
搜了一下,虽然没明白楼主的问题,但是搞明白一个事情:
VC中,根据调用方式不同,函数名也会有所区别,

关键字 堆栈清除者 参数传递
__cdecl 调用者 从右向左的顺序压入堆栈内
__stdcall 被调用者 从右向左的顺序压入堆栈内
__fastcall 被调用者 保存在寄存器中,然后其他的压入堆栈内
thiscall(非关键字) 被调用者 压入堆栈,this指针保存在ECX寄存器内

调用方式解析:
void calltype MyFunc( char c, short s, int i, double f );
calltype代表不同的调用方式

__cdecl调用:
在VC中的编译器选项是/Gd。这是C和C++程序的缺省函数调用转换方式。由于堆栈是由调用者清除的,所以它能调用vararg函数。以__cdecl 调用方式编译的程序比__stdcall大,因为以__stdcall方式编译的程序需要在每个函数调用中包含堆栈清空的代码。
以C方式修饰的函数名是_MyFunc。

__stdcall调用:
在VC中的编译器选项是/Gz。
以C方式修饰的函数名是_MyFunc@20。20是参数的字节数(5×4bytes)。C++方式修饰的名称是私有的,各个编译器可能不同。

__fastcall调用:
在VC中的编译器选项是/Gr。
以C方式修饰的函数名是@MyFunc@20。C++方式修饰的名称是私有的,各个编译器可能不同。

thiscall调用:
这是无参C++成员函数的默认调用方式。调用者负责清空堆栈,this指针第一个入栈。因为没有对应的关键字,所以thiscall方式的调用不可在程序中被显式定义。所有的函数参数都压入堆栈。这种调用方式只应用于C++,所以没有C方式的命名修饰。
fierygnu 2005-12-30
  • 打赏
  • 举报
回复
function1@12,怎么出来个@12?
thenocturne 2005-12-30
  • 打赏
  • 举报
回复
我晕了,刚才我用VC生成了一个C静态库,其中有一个C函数__stdcall function2(...)
让MinGW下的gcc链接这个C静态库,成功了。用nm看那个VC生成的静态库,生成函数名
是_function2。这次gcc怎么就认出来了呢?我把库改掉,让它不包含function2的定义,
gcc链接就报错: undefined reference to `function2`.这样看来gcc为__stdcall函数
生成的函数名是没有下划线的,可它怎么就能认出VC生成的_function2不能认出那个第三
方库的_function1呢?晕了。
thenocturne 2005-12-30
  • 打赏
  • 举报
回复
是这样的,第三方的头文件里面这样声明的:

#ifdef __cplusplus
extern "C" {
#endif

...
extern __stdcall function1(...);
...

#ifdef __cplusplus
}
#endif

照理说他的库就该是C库了。但是我用nm看那个库里面的的函数名是:_function1。
这个_应该是对应__stdcall而加上的。至少win32下的C编译器会这样。我觉得问题
应该是gcc在编译时对于__stdcall的C函数不会在生成函数名前加 _ ,或者只是MinGW
下的gcc是这样。有UNIX/LINUX环境的朋友能帮忙验证一下么?:)


x86 2005-12-30
  • 打赏
  • 举报
回复
试一下
extern C _stdcall function1(...)

而且那个_stdcall 是否可以不要?你看看你的库有没有提供头文件

而且mingw也有nm命令的(c:\dev-cpp\bin),在命令行运行。
fierygnu 2005-12-30
  • 打赏
  • 举报
回复
用-l连接了吗?第三方的库是C还是C++?
thenocturne 2005-12-30
  • 打赏
  • 举报
回复
谢谢楼上几位的回答,我碰到的问题是这样的。我用MinGW下的gcc编译一个C程序,其中用到了第三方的静态库函数function1。我在自己的代码中包含了该库对应的第三方头文件,其中声明:
extern _stdcall function1(...)
结果在编译中就出现了问题:undefined reference to 'function1@12'。也就是说MinGW gcc为function1生成的文件名为function1@12而不是_function1@12。同样的代码在VC下就可以编译通过并正常运行,我看了一下VC为extern _stdcall function1(...)生成的函数名就是_function1@12。所以我认为该第三方库里面的函数名就是_function1@12而不是function1@12。

是不是MinGW下的gcc和其它版本的gcc在处理这个问题上不一样呢?
x86 2005-12-30
  • 打赏
  • 举报
回复
你用strings或者nm命令看.so或者.a里面的符号, 可以看到函数名字是不变的.
不过用g++编译的话名字就会按照c++的规则根据参数和返回值改变。

比如简单的一个函数
int test(int a) {
}

gcc编译,用nm看:
00000005 T main
00000000 T test

g++编译,用nm看:
00000000 T _Z5testi
00000006 T main
fierygnu 2005-12-30
  • 打赏
  • 举报
回复
C编译器是一样的。

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧