我在研究“Unix编程环境”(1983)一书中的一些例子的同时,读了一些特殊的C代码。
作为一种好奇心,我想了解更多关于它的信息,让我们称之为" style"。这里的兴趣点是int main(argc, argv)
#include <stdio.h>
int main(argc, argv)
char *argv[];
{
printf("%s\n", argv[0]);
return 0;
}
在我的调查中,我发现使用标记-Wall -pedantic -ansi
编译上述代码时没有任何警告,并将-ansi
替换为更新的-std=c99
(或{{ 1}},c11
和gcc
}仅警告cc
默认为argc
。
我仔细阅读了旧的C89标准,试图找到这种特殊写作方式的参考 但是我自己找不到任何东西,所以我顺从了集体的更多知识。
因此,问题是,这个深奥的写作从什么时候开始,可能为什么仍然允许(遗留原因?)
答案 0 :(得分:4)
旧的做事方式是拥有没有原型的功能。函数默认返回int
,并且由于调用站点的函数参数类型未知,因此最好将其正确。这使您无需维护头文件,但由于各种原因,不再推荐使用它。
// In func.c
// Default to int return
func(x, y)
int x;
int y;
{
return x + y;
}
// In main.c
main(argc, argv)
int argc;
char **argv;
{
int result = func(2, 3);
}
如果功能参数类型错误,则会导致问题。
int result = func(2.0, 3,0); // Wrong, but no compiler error or warning
在不包含相关头文件的情况下调用函数是正常的。但是你需要声明函数返回类型。
// This is NOT a function prototype, it just declares the return type.
double sin();
double one = sin(3.14); // Correct
double zero = sin(0); // WRONG
double zero = sin(0.0); // Correct
标准仍允许使用旧样式函数,但默认返回类型已消失。这允许您编译旧程序。对于新程序,GCC中的-Wmissing-prototypes
选项可帮助您避免意外使用旧样式。
int func(); // Old-style, can take any number of arguments.
int func(void); // New-style, takes no arguments, is a function prototype.
答案 1 :(得分:2)
这是老式的K&R C。
默认情况下,一切都是整数,您可以在函数中定义实际的参数类型,而不是在原型中,而是在单独的声明列表中。它使编写整数代码更容易,但使调试函数调用成为一场噩梦。
这是一个用两种风格编写的函数。
int myFunc(const char *from, char *to, int len); // Ah that feels right, doesn't it
int myFunc(const char *from, char *to, int len){} // And here's the definition
myKRFunc(); /* Okay, that's a declaration */
myKRFunc(from, to, len) /* Yep, you just write the parameter names here */
char *from, *to; /* And you can write normal declarations, len defaults to an int */
{}
我想解释为什么没有原型的调试函数调用更难,但Dietrich在他的答案中很好地介绍了它。
答案 2 :(得分:1)
这是最初的K&amp; R风格C.它仍然合法,因为为什么不呢?向后兼容性让人们可以小步前进。这是任何流行的演变系统的痛苦。
答案 3 :(得分:0)
这是基于旧的“标准”,所以我不会太担心它。我绝对不建议使用那种风格进行编程,但如果遇到更多遗留代码,知道它存在是很有用的。