Joh*_*ohn 76 c syntax function
我是C的新手.我遇到过一种我以前从未见过的函数语法形式,参数类型在参数列表之后定义.有人可以向我解释它与典型的C函数语法有何不同?
例:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
Run Code Online (Sandbox Code Playgroud)
Fer*_*cio 65
这是参数列表的旧式语法,仍然受支持.在K&R C中,您也可以省略类型声明,它们将默认为int.即
main(argc, argv)
char *argv[];
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将是相同的功能.
Joh*_*itb 28
有趣的是函数的调用约定差异,以及没有原型的函数.考虑旧样式定义:
void f(a)
float a; {
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,调用约定是在传递给函数之前提升所有参数.因此,如果f接收到double但参数具有类型float(完全有效),则编译器必须发出代码,在执行函数体之前将double转换为float.
如果包含原型,则编译器不再执行此类自动提升,并且传递的任何数据都将转换为原型参数的类型,就像通过赋值一样.因此以下内容不合法,导致未定义的行为:
void f(float a);
void f(a)
float a; {
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,函数的定义会将提交的参数从double(提升的形式)转换为float因为定义是旧式的.但是参数是作为float提交的,因为该函数有一个原型.您解决矛盾的选择有两个:
// option 1
void f(double a);
void f(a)
float a; {
}
// option 2
// this declaration can be put in a header, but is redundant in this case,
// since the definition exposes a prototype already if both appear in a
// translation unit prior to the call.
void f(float a);
void f(float a) {
}
Run Code Online (Sandbox Code Playgroud)
如果你有选择,首选应该是首选,因为它预先摆脱了旧的样式定义.如果函数的这些矛盾函数类型出现在同一个转换单元中,编译器通常会告诉您(但不是必需的).如果在多个翻译单元上出现此类矛盾,则错误可能会被忽视,并且可能导致难以预测的错误.最好避免使用这些旧样式定义.
没有区别,只是这是 C 中函数声明的旧语法——它是在 ANSI 之前使用的。除非您打算将其提供给 80 年代的朋友,否则切勿编写此类代码。此外,永远不要依赖于隐式类型假设(正如另一个答案似乎暗示的那样)
虽然函数定义的旧语法仍然有效(如果您询问编译器,则会出现警告),但使用它们并不提供函数原型。
\n如果没有函数原型,编译器将不会检查函数是否被正确调用。
#include <stdio.h>\nint foo(c)\nint c;\n{ return printf("%d\\n", c); }\n\nint bar(x)\ndouble x;\n{ return printf("%f\\n", x); }\n\nint main(void)\n{\n foo(42); /* ok */\n bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当程序运行时,我机器上的输出是
\n\n$ gcc proto.c\n$ gcc -Wstrict-prototypes proto.c\nproto.c:4: warning: function declaration isn\xe2\x80\x99t a prototype\nproto.c:10: warning: function declaration isn\xe2\x80\x99t a prototype\n$ ./a.out\n42\n0.000000\nRun Code Online (Sandbox Code Playgroud)\n