繁体   English   中英

__cdecl在C中的函数参数中有什么用

[英]What's the use of __cdecl in function arguments in C

我正在学习C语言,在学习的同时发现了一行代码,这对我来说是全新的并且很奇怪void PullDown(char **, int, void (__cdecl **)(void)); 我只知道第一和第二参数。 我想了解第三个参数。 __cdecl之后的两个星号有什么用? 我从这种语法(type_cast *)知道,所以它与类型转换有关?

__cdecl是Microsoft编译器支持的C语言扩展 它明确指定了应使用“ cdecl”调用约定来调用函数,该约定与调用函数前后为传递参数和返回值而应如何正确设置寄存器和堆栈的状态有关。 。

在您的代码段中, PullDown被定义为具有三个参数的函数,其中前两个为char **int

函数的最后一个参数void (__cdecl **)(void) cdecl void (__cdecl **)(void)是指向具有cdecl调用约定的函数的指针,该约定没有返回值且不包含任何参数。

为了分解该声明,我们现在可以完全删除__cdecl并为此参数添加一个变量名:

void (**param)(void)

声明中的*运算符指定其右边的表达式为指针,因此这意味着param是指针,并且*param是指针(因此param是指向指针的指针)。 要了解此指针指向的内容,可以将**param替换为占位符foobar以提供以下信息:

void (foobar)(void)

现在,它具有一对多余的括号,并等效于以下内容:

void foobar(void)

现在,这看起来像一个普通的函数声明返回voidvoid参数(没有参数和返回值)。 因此, param是指向具有此签名的函数的指针。

最后, __cdecl适用于它右侧的表达式,并且由于**param表示该函数,因此可以在**param左侧添加__cdecl ,以表明该函数具有cdecl调用约定:

void (__cdecl **param)(void)

代码段中的参数只是删除了参数名称param ,就像从char **paramint param删除int param

一般来说,使用Visual Studio编译C和C ++代码时,默认的cdecl调用约定应该是默认的,因此显式指定__cdecl应该是多余的。 但是,有时需要指定某个函数具有__stdcall调用约定,并且在处理函数指针时务必确保仅通过__stdcall函数指针来调用stdcall函数,而仅通过__cdecl函数来调用cdecl函数,这一点很重要。指针(应为默认值)。 尝试使用错误的调用约定来调用函数很可能会导致程序崩溃或使其处于不确定状态。

第三个参数是指向函数指针的指针。 仅使用一个星号,它将是函数指针。

__cdecl是特定于编译器的属性,指示必须使用C调用约定。 参见本页 如果只使用C或其他编译器,则可以忽略它。

也许例子会有所帮助:

#include <stdio.h>

void PullDown(char **, int, void (**)(void));

int main(int argc, char **argv)
{
    void (*fun)(void);
    PullDown(NULL, 0, &fun);
    fun();
    return 0;
}

void my_function(void)
{
    printf("Hello!\n");
}

void PullDown(char **param1, int param2, void (**param3)(void))
{
    *param3 = my_function;    
}

它打印“你好!”

在该示例中, fun是函数指针变量。 fun指针传递给PullDown()函数调用。 因此PullDown()可以将my_function()指针设置为fun

  • void (*)(void)是指向void func (void)类型的函数的函数指针。

  • void (**)(void)是指向函数指针的指针。 可能的含义是调用者希望此参数被写入,以便将函数指针传递回调用者。

  • void (__cdecl **)(void)相同,但具有非标准扩展名__cdecl 这指定了函数的调用约定,即谁负责堆栈参数。 如果是调用方,则使用__cdecl ;如果是函数,则使用__stdcall Windows编程中通常使用这两个非标准扩展。

    在这种情况下,它为所指向的函数指定调用约定。

__cdecl是默认C / C ++调用约定的标签(令人吃惊地命名为cdecl )。 简而言之,调用约定是描述如何在汇编中调用函数的一组规则(例如,将参数放入寄存器/堆栈,从EAX / RAX寄存器或其他位置获取结果)。 您可以在相应的Wiki页面上阅读有关这些约定的更多信息。

您所拥有的是函数PullDown ,它PullDown 3个参数,第三个是指向应满足cdecl约定的函数的指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM