在函数名列表后写C函数参数类型,并且某些参数没有类型

6

在学习 《Unix编程环境》(1983年)一书中的一些示例时,我读到了一些对我来说很奇怪的C代码。

作为一个好奇心,我想更多地了解这种“风格”。这里感兴趣的点是 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(或者使用gccccc11)只会警告argc默认为int
我研究了旧的C89标准,试图找到关于这种特定写法的参考资料,但是自己没有找到任何内容,所以我转而求助于更广泛的知识群体。
因此,问题来了:这种神秘的写法从什么时候开始,可能为什么仍然被允许(遗留原因?)

6
这被称为“K&R”风格,是C语言的第一批实现所设定的事实标准,并在Kernighan和Ritchie书的第一版中有所记录。没有包含类型的声明默认为“int”,而参数的类型是以你提供的方式进行的。没有函数原型,只有函数声明。C89标准添加了原型,但也支持K&R风格作为合法的遗留代码。 - Michael Burr
4个回答

7

过去的做法是没有原型的函数。这些函数默认返回 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.

3

这是传统的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

这是原始的K&R风格的C语言。它仍然是合法的,因为为什么不呢?向后兼容性让人们可以以小步前进。这就是任何流行演变系统的痛点。


0

这是基于旧的“标准”,所以不必太担心。我绝对不建议以那种风格编程,但如果你遇到更多的遗留代码,了解它的存在是有用的。


它不基于任何“旧标准”。在1983年,C语言并没有一个标准。 - Wooble
3
我将“标准”用引号括起来 :) - R. Barzell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接