[VC]函数调用约定解析(C/C++)
C/C++函数调用约定和函数名称修饰规则探讨
作者:星轨(oRbIt)
使用C/C++语言开发软件的程序员经常碰到这样的问题:有时候是程序编译没有问题,但是链接的时候总是报告函数不存在(经典的LNK
2001错误),有时候是程序编译和链接都没有错误,但是只要调用库中的函数就会出现堆栈异常。这些现象通常是出现在C和C++的代码混合使用的情况下或
在C++程序中使用第三方的库的情况下(不是用C++语言开发的),其实这都是函数调用约定(Calling
Convention)和函数名修饰(Decorated
Name)规则惹的祸。函数调用方式决定了函数参数入栈的顺序,是由调用者函数还是被调用函数负责清除栈中的参数等问题,而函数名修饰规则决定了编译器使
用何种名字修饰方式来区分不同的函数,如果函数之间的调用约定不匹配或者名字修饰不匹配就会产生以上的问题。本文分别对C和C++这两种编程语言的函数调
用约定和函数名修饰规则进行详细的解释,比较了它们的异同之处,并举例说明了以上问题出现的原因。
函数调用约定(Calling Convention)
函数调用约定不仅决定了发生函数调用时函数参数的入栈顺序,还决定了是由调用者函数还是被调用函数负责清除栈中的参数,还原堆栈。函数调用约定有很多方
式,除了常见的__cdecl,__fastcall和__stdcall之外,C++的编译器还支持thiscall方式,不少C/C++编译器还支持
naked
call方式。这么多函数调用约定常常令许多程序员很迷惑,到底它们是怎么回事,都是在什么情况下使用呢?下面就分别介绍这几种函数调用约定。
1.__cdecl
编译器的命令行参数是/Gd。__cdecl方式是C/C++编译器默认的函数调用约定,所有非C++成员函数和那些没有用__stdcall或
__fastcall声明的函数都默认是__cdecl方式,它使用C函数调用方式,函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数,由
于每次函数调用都要由编译器产生清除(还原)堆栈的代码,所以使用__cdecl方式编译的程序比使用__stdcall方式编译的程序要大很多,但是
__cdecl调用方式是由函数调用者负责清除栈中的函数参数,所以这种方式支持可变参数,比如printf和windows的API
wsprintf就是__cdecl调用方式。对于C函数,__cdecl方式的名字修饰约定是在函数名称前添加一个下划线;对于C++函数,除非特别使
用extern
"C",C++函数使用不同的名字修饰方式。
2.__fastcall
编译器的
相关文档:
2.1 可测性问题详解(2)
接下来我们讨论重点问题:覆盖输入。一个函数,输入会有哪些呢?输入包括两方面:外部输入,内部输入。外部输入容易理解,就是函数外部可以设定的输入,包括参数,全局变量,成员变量。
&nb ......
BSS
未初始化的数据
DATA
初始化的数据
TEXT(code)
代码
在C中有全局、局部(自动变量)和静态变量。
全局变量在C语言里表示时,在函数之外的就是全局变量,即在函数外所申明的变量;而静态变量可以放在函数外,也可以放在函数内。全局变量有两个作用:第一,当在函数外申 ......
C/C++: 十六进制转10进制源码
收藏
view plain
copy to clipboard
print
?
int
hex_char_value(
char
c)
{
if
(c >=
'0'
&& ......