在C语言中理解函数原型

3
为什么以下程序能正常工作?
int main()
{
    int x;
    x = foo();
    printf("%d",x);
    getchar();
    return 0;
}

int foo()
{
    return 2;
}

而不是这个程序吗?
//double function(void);

int main(){
    double val;
    val = function();
    printf("%ul\n",val);
}

double function(void){
    double num;
    num = DBL_MAX;
    printf("%ul\n",num);
    return num;
}

在我看来,这两种情况下函数的定义在main()之前都不存在。那么为什么第一种情况下编译器在main()之前没有函数定义时仍然调用该函数,而第二种情况下却不会呢?

请注意,旧的C标准(C99)和当前的C标准(C11)都规定程序应该生成诊断信息。只有过时的(C89/C90)标准允许第一个程序工作,而第二个程序总是失败的。如果你喜欢使用错误的代码,那么可以按照较为宽松的C89标准编写。这些宽松的规则是历史上的必要条件。没有这种宽松性,标准就不可能成功。但是,旧标准已经15年了,你应该使用它,并在使用没有原型的函数时让你的编译器发出警告。如果你的编译器不能做到这一点,那就换一个更好的编译器。 - Jonathan Leffler
@JonathanLeffler,%ul 可以用于 double 吗? - Spikatrix
printf()的格式字符串中吗?不是的;%ul格式化一个无符号整数,后面跟着一个字母l,它不是转换说明的一部分。如果你想用%lu,那么它将会格式化一个无符号长整型。当你将一个double作为相应值放入参数列表时,这两个选项都不是有用的(或者甚至不可靠)。 - Jonathan Leffler
@JonathanLeffler,糟糕!我以为%ul需要一个unsigned long。我混淆了%ul%lu。那么,您是在告诉我如果使用%lu打印double会导致UB吗? - Spikatrix
@CoolGuy:是的,绝对不要尝试使用任何整数格式打印double。例如,浮点值可能会从整数值分别传递到寄存器中,因此当它看到整数格式时,它会从完全错误的位置读取。使用M68k芯片的计算机曾经在An寄存器中返回指针,在Rn寄存器中返回整数;如果您没有告诉它函数返回指针,编译器将生成代码以从错误的位置读取。我不记得这些芯片如何处理浮点返回。等等。 - Jonathan Leffler
如果任何答案对您有帮助,请将其标记为已接受。 - aakansha
3个回答

7

由于隐式函数声明,编译器默认未指定的类型为int

在第一个情况下这是巧合,但在第二个情况下不是。


6

任何称为C函数的东西默认都是int类型,没有参数(例如在您的第一个示例中)。如果编译器找到符合条件的函数,则不会出现错误。

在第二种情况下,编译器将main()函数编译为int类型,但随后发现这不是真的,并报告了一个错误!

注释:Jonathan Leffler评论说:

仅适用于C89/C90。不适用于C99;不适用于C11。当然,一些供应商仍然只实现C89;微软是一个显著的例子!


2
仅适用于C89/C90。不适用于C99,也不适用于C11。当然,一些供应商仍然只实现C89,其中一个著名的例子就是Microsoft! - Jonathan Leffler
很有趣!我会把它添加到回复中(这些评论可能在某个时间被删除)。 - jcoppens

1

在C语言中,如果定义了一个函数,则其隐式返回类型为int

  • 在第一种情况下,函数的返回类型为int,因此main()识别该函数并且编译不会出现任何错误。

  • 在第二种情况下,函数的返回类型为double,因此main()无法识别该函数,从而生成错误,因此需要声明函数的原型。

此外,在旧版本中(直到C89),如果未提及返回类型,则隐式认为其为int

在C99标准中,即使返回类型是int,也不允许省略返回类型。

有关更多详细信息,请查看:隐式返回类型C


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