我知道你可能会认为这个问题已经得到了回答,但事实并非如此,或者至少对我来说不是很清楚。
int WINAPI WinMain (){}
这是着名的winmain
函数的伪形式。
我的问题是关于“回复类型”和“函数名称”之间的调用约定WINAPI
,,特别是它的位置。这是标准C吗?因为我引用了Brian W. Kernighan和Dennis M. Ritchie的书,我没有看到这种形式。
我也搜索了它的含义,他们说这是放置_stdcall
的宏。所以请不要告诉我这个问题是重复的。
这是其中一个可能非常接近我的问题 What does "WINAPI" in main function mean?
我想要一个明确的答案WINAPI
:它是标准的C吗?所以我可以在任何函数声明中的返回类型之后放置一个调用约定然后我将它赋予<世界上强大的>任何 C编译器?或者它是否只适用于Microsoft编译器?如果是这样,任何人都可以将他们的规则强加于C语法吗?
对不起,我知道我的问题可能对你们许多人来说都是微不足道的,但我到处搜索了函数声明语法,并且所有来源都拒绝了这个调用约定的地方。
答案 0 :(得分:3)
基本答案:不可以.C语言标准定义的函数声明在返回类型和函数名之间没有元素。所以int __bootycall myFunc(int qux)
不是标准的C(或C ++),即使C实现被允许保留__customIdentifiers
供自己专用。
然而
需要使用call-convention说明符(例如__cdecl
);很多(特别是早期的非UNIX [特别是MS-DOS])平台有多个调用约定可供选择,并且指定函数的调用约定与参数列表一样重要,如果不是更重要的话。那个功能。因此需要在那里插入一些额外的东西。
当时(甚至在C89之前),没有针对体系结构特定的功能属性做出规定(可能是因为C,仅为实现UNIX实用程序而设计,并不需要任何功能)。这将在C99中得到补救,如果C99在那时存在,那很可能是__cdecl
等。将是函数属性,而不是那里的随机标识符。但事实上,当需要指定非默认调用约定时,有四个合理的位置:在返回类型之前,返回类型和函数名之间,函数名和开头括号之间参数列表,以及参数列表之后。
我在这里推测,但似乎第二种选择最有意义。这是前C ++,请记住;没有post-arglist - const
,并且在返回类型之前唯一可以显示的是static
,它指定了链接而不是关于函数本身。在函数名之前或之后离开,并将函数名与其参数列表分开会降低可读性。这使得返回类型和函数名称之间略微不寻常的位置成为最好的一堆。
其余的都是历史。后来的编译器利用新生的__attribute__
语法将调用约定关键字放在一个更合适的位置,但是基于DOS的编译器(其中Microsoft C是其中之一)在返回类型之后推送它。
答案 1 :(得分:2)
你明确问题的答案:
WINAPI
,这是标准的C吗?
是否。__stdcall
是Microsoft扩展名。
答案 2 :(得分:2)
__stdcall
和关键字的位置都是Microsoft特定的。任何编译器供应商都能够在其实现中添加非标准语法。
在this MSDN文章的最顶部:
Microsoft特定
它还提到了页面末尾的WINAPI
宏:
在下面的示例中,使用__stdcall会导致所有WINAPI函数类型作为标准调用处理:[...]`
此表单适用于Microsoft C ++编译器和MinGW工具链,后者实现了Windows的GCC。
但一般来说,GCC使用其他形式使用它的属性:
int WinMain() __attribute__((stdcall)) // or WINAPI if using the macro
{}
但是,通过使用最近的C++11 generalized attributes,我们可能会在未来使用更标准的语法(stdcall
部分仍然是平台特定的)。
[[ms::stdcall]]
int WinMain() {}
答案 3 :(得分:1)
WINAPI
是windows.h
中定义的宏,扩展为__stdcall
。 windows.h
和__stdcall
都是特定于Windows的 - 没有行业标准定义其含义的任何方面。
C和C ++标准确实定义了对函数定义具有相关影响的关键字:inline
,_Noreturn
(C2011)和static
。所有这些关键字通常都放在之前返回类型,但如果我正确读取C2011,语法实际上并不需要这样做:你可以写得很好
int static foo(void) { return 42; }
这些关键字称为函数说明符和存储类说明符。 不要将它们与类型说明符和类型限定符混淆,它们也可以出现在这个位置,但是当它们出现时修改返回类型。 / p>