函数调用约定与函数名称修饰规则三呢
函数调用约定和名字修饰规则不匹配引起的常见问题 函数调用时如果出现堆栈异常,十有八九是由于函数调用约定不匹配引起的。比如动态链接库a有以下导出函数:
long MakeFun(long lFun);
动态库生成的时候采用的函数调用约定是__stdcall,所以编译生成的l中函数MakeFun的调用约定是_stdcall,也就是函数调用时参数从右向左入栈,函数返回时自己还原堆栈。现在某个程序模块b要引用a中的MakeFun,b和a一样使用C++方式编译,只是b模块的函数调用方式是__cdecl,由于b包含了a提供的头文件中MakeFun函数声明,所以MakeFun在b模块中被其它调用MakeFun的函数认为是__cdecl调用方式,b模块中的这些函数在调用完MakeFun当然要帮着恢复堆栈啦,可是MakeFun已经在结束时自己恢复了堆栈,b模块中的函数这样多此一举就引起了栈指针错误,从而引发堆栈异常。宏观上的现象就是函数调用没有问题(因为参数传递顺序是一样的),MakeFun也完成了自己的功能,只是函数返回后引发错误。解决的方法也很简单,只要保证两个模块的在编译时设置相同的函数调用约定就行了。
在了解了函数调用约定和函数的名修饰规则之后,再来看在C++程序中使用C语言编译的库时经常出现的LNK 2001错误就很简单了。还以上面例子的两个模块为例,这一次两个模块在编译的时候都采用__stdcall调用约定,但是l使用C语言的语法编译的(C语言方式),所以l的载入库b中MakeFun函数的名字修饰就是“_MakeFun@4
”。b包含了a提供的头文件中MakeFun函数声明,但是由于b采用的是C++语言编译,所以MakeFun在b模块中被按照C++的名字修饰规则命名为“?MakeFun@@YGJJ@Z”,编译过程相安无事,链接程序时c++的链接器就到b中去找?MakeFun@@YGJJ@Z
”,但是b中只有“_MakeFun@4
也是中国关于不正当竞争案最重的判罚。至此 没有?MakeFun@@YGJJ@Z
”,于是链接器就报告:
error LNK2001: unresolved external symbol ?MakeFun@@YGJJ@Z
解决的方法和简单,就是要让b模块知道这个函数是C语言编译的,extern \"C\"可以做到这一点。一个采用C语言编译的库应该考虑到使用这个库的程序可能是C++程序(使用C++编译器),所以在设计头文件时应该注意这一点。通常应该这样声明头文件:
#ifdef _cplusplus
extern \"C\" {
#endif
long MakeFun(long lFun);
#ifdef _cplusplus
}
#endif
这样C++的编译器就知道MakeFun的修饰名“_MakeFun@4
”,就不会有链接错误了。
许多人不明白,为什么我使用的编译器都是VC的编译器还会产生“error LNK2001”错误?其实,VC的编译器会根据源文件的扩展名选择编译方式,如果文件的扩展名是“.C”,编译器会采用C的语法编译,如果扩展名是“.cpp”,编译器会使用C++的语法编译程序,所以,最好的方法就是使用extern \"C\"。
妇科用药成都治疗卵巢炎多少钱
兰州白癜风治疗医院
- 上一页:函数调用约定与函数名称修饰规则一牛
- 下一页:函数调用约定与函数名称修饰规则二的
-
微信原先增加这个功能!
、 5月20日 网易公布最新公告 网易视频号的平台 将展示出客户端IP归属 全文...
2024-12-18
-
女人们过了50岁,夏天穿裙子记住“三不要”原则,显老不说还没气质
对于女人们来说,50岁是一个如此一来,无论是身体静止状态还是心态各个方...
2024-12-11
-
高中学历,应该从什么简而言之提升自己的学历?
1.如果你年龄还小,高三、高中时教书,或者几天后初中部时毕业考虑要不让...
2024-12-10
-
求函数最值,一般方法和解决办法,和你想的可能不一样
求取formula_最绝对值的情况,相信大家都不陌生。平时我们用得最多的步骤,...
2024-12-07
-
曾年销30亿的“神酒”江小白,为何如今无人问津?假象原因太现实
曾年销30亿的“神茶”江边小鸟,为何而今无人问津?背后原因太现实要一切...
2024-11-27
-
总分毕业设计!男生用1400斤钢筋铸工人雕塑:向父亲和建造者致敬
新闻记者 | 周盾 兼职 | 刘至 6月18日,广州美术学院人像专业知识学生陈锦亿...
2024-11-10