是的,我知道"Cdecl"是一个著名的调用约定名称,所以请不要向我解释调用约定。我想问的是缩写"Cdecl"实际上代表什么。我认为这是一个糟糕的命名选择,因为乍一看它让人想起"C declarator"(C语言中相当独特的语法方面)。实际上,有一个名为cdecl的程序,其唯一目的是解密C declarators。但据我所知,C declarator语法与调用约定完全无关。
简化版: "stdcall"代表"标准调用约定"。那么"cdecl"代表什么?
是的,我知道"Cdecl"是一个著名的调用约定名称,所以请不要向我解释调用约定。我想问的是缩写"Cdecl"实际上代表什么。我认为这是一个糟糕的命名选择,因为乍一看它让人想起"C declarator"(C语言中相当独特的语法方面)。实际上,有一个名为cdecl的程序,其唯一目的是解密C declarators。但据我所知,C declarator语法与调用约定完全无关。
简化版: "stdcall"代表"标准调用约定"。那么"cdecl"代表什么?
它来源于被声明的 C 函数(与在 K&R C 中常见的未声明的 C 函数相对)。
那时它与 pascal 调用约定共存(其中被调用者清空堆栈),因此在编程语言之后称它有点说得通。
int main() { char c = 0; f(c); }
传递了一个int
,而在二进制代码中,尽管参数类型为char
,但void f(c) char c; { }
需要将参数数据读取为int
。如果你在作用域内有void f(char c)
和void f(char c) { }
,那么数据将被传递并读取为char
。 - Johannes Schaub - litb你对此过于深究了。它代表了调用C函数的实现惯例,这在使用可变参数时尤为重要。
它不一定是"C"和"declaration"的组合缩写; 名称只是名称,尤其是在编程中。助记符有帮助,但是就像"malloc"意味着"分配内存"一样,它有附加的含义,而我们也知道并将其赋予了它的额外含义; "alloca" 也是"分配内存"的意思,例如。
或者以"struct"为例,它的“意思”是“结构”,但是“结构”本身太过普通,如果没有我们下意识地赋予“struct”的附加含义,我们将会彻底迷失——就像新手程序员还在学习术语时常常迷失。
C声明。由C引入的声明。
[编辑]
说实话,我不确定这是否就是它的含义,尽管它确实是由C引入的。但由于调用者必须清理已分配的内存(与大多数其他调用约定不同),它也可能是“Caller Does End CLeaning”的缩写,我认为这实际上是一个很好的记忆辅助方法。:D
cdecl
(C声明)调用约定通常是x86 C编译器的默认调用约定。在计算机科学中,调用约定是子程序如何从其调用者接收参数以及如何返回结果的实现级别(低级别)方案。各种实现的差异包括放置参数、返回值、返回地址和作用域链接的位置(寄存器、堆栈或内存等),以及准备函数调用和恢复环境的任务如何在调用者和被调用者之间分配。
调用约定可能与特定编程语言的求值策略有关,但通常不被认为是其一部分(或反之),因为求值策略通常在更高的抽象级别上定义,并被视为语言的一部分,而不是特定语言编译器的低级实现细节。
cdecl
(意为C类型声明)是一种调用约定,起源于Microsoft的C编程语言编译器,并被许多x86体系结构的C编译器所使用。在中,子例程参数通过堆栈传递。整数值和内存地址在EAX
寄存器中返回,浮点值在ST0
x87寄存器中返回。寄存器EAX
、ECX
和EDX
由呼叫者保存,其余由被呼叫者保存。x87浮点寄存器ST0
到ST7
在调用新函数时必须为空(出栈或释放),而在退出函数时,ST1
到ST7
必须为空。ST0
在不用于返回值时也必须为空。int callee(int, int, int);
int caller(void)
{
return callee(1, 2, 3) + 5;
}
caller:
; make new call frame
; (some compilers may produce an 'enter' instruction instead)
push ebp ; save old call frame
mov ebp, esp ; initialize new call frame
; push call arguments, in reverse
; (some compilers may subtract the required space from the stack pointer,
; then write each argument directly, see below.
; The 'enter' instruction can also do something similar)
; sub esp, 12 : 'enter' instruction could do this for us
; mov [ebp-4], 3 : or mov [esp+8], 3
; mov [ebp-8], 2 : or mov [esp+4], 2
; mov [ebp-12], 1 : or mov [esp], 1
push 3
push 2
push 1
call callee ; call subroutine 'callee'
add esp, 12 ; remove call arguments from frame
add eax, 5 ; modify subroutine result
; (eax is the return value of our callee,
; so we don't have to move it into a local variable)
; restore old call frame
; (some compilers may produce a 'leave' instruction instead)
mov esp, ebp ; most calling conventions dictate ebp be callee-saved,
; i.e. it's preserved after calling the callee.
; it therefore still points to the start of our stack frame.
; we do need to make sure
; callee doesn't modify (or restores) ebp, though,
; so we need to make sure
; it uses a calling convention which does this
pop ebp ; restore old call frame
ret ; return
return_type __cdecl func_name();
其他约定:
DECLARE SUB Foo ()
DECLARE FUNCTION Foo ()
DECLARE SUB Foo CDECL ()
DECLARE FUNCTION Foo CDECL ()
CDECL没有缩写,它只是调用约定的名称。
如果这不是你要找的,而实际上是关于CDECL的历史:
这是一种微软特定的调用约定属性(在介绍时期介于1985年至1995年之间),后来成为标准。
太糟糕了,页面从互联网上消失了(wayback也没有),但是谁有旧的MSDN CD可能会在“C语言参考”内找到主题“声明摘要”,其中清楚地说明如下:
attribute-seq:/* attribute-seq是Microsoft特定的*/
attribute attribute-seq opt attribute:其中之一/* Microsoft Specific */
__asm __fastcall __based __inline __cdecl __stdcall
同样在同一份旧的MSDN文档中__cdecl
__cdecl 主页 | 概述 | 如何操作更新 在看到评论指出我的错误后,我已经完全修订了这篇文章。 cdecl
表示该函数使用与 C
函数相同的调用约定。此外,extern "C"
还表示该函数名不应该经过 C++
的名称重整。
至于为什么它被称为 cdecl
,我不知道了。
cdecl
。你也是在胡说八道!" - David Heffernan_cdecl
(事实上,除非它是非静态成员函数,在大多数编译器中这是默认的,否则就是_thiscall)。 - Billy ONeal