4

希望这是一个非常简单的问题。以下是我拥有的 C pgm (test.c)。

#include <stdio.h>
//#include <stdlib.h>

int main (int argc, char *argv[]) {
    int intValue = atoi("1");
    double doubleValue = atof("2");
    fprintf(stdout,"The intValue is %d and the doubleValue is %g\n", intValue, doubleValue);
    return 0;
}

请注意,我使用的是 stdlib.h 中的 atoi() 和 atof(),但我不包含该头文件。我编译了 pgm (gcc test.c) 并且没有编译器错误!

我运行 pgm (./a.out),这是错误的输出。

The intValue is 1 and the doubleValue is 0

现在我包含stdlib.h(通过删除#include 之前的注释)并重新编译并再次运行它。这次我得到了正确的输出:

The intValue is 1 and the doubleValue is 2

为什么编译器没有抱怨不包括 stdlib.h 并且仍然让我使用 atoi()、atof() 函数?

我的 gcc 信息:

$ gcc --version
gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-27)

任何想法表示赞赏!

4

5 回答 5

13

由于历史原因——特别是与非常古老的 C 程序(C89 之前)的兼容性——使用没有首先声明的函数只会引发来自 GCC 的警告,而不是错误。但是这种函数的返回类型被假定为int,而不是double,这就是程序执行不正确的原因。

如果你-Wall在命令行上使用,你会得到一个诊断:

$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:5: warning: implicit declaration of function ‘atoi’
test.c:6: warning: implicit declaration of function ‘atof’

你应该-Wall基本上总是使用。新代码的其他非常有用的警告选项是-Wextra-Wstrict-prototypes-Wmissing-prototypes-pedantic-Wwrite-strings,但与-Wall它们相比,误报率要高得多。

切线:从不使用atoinor atof,它们隐藏输入错误。使用strtolandstrtod代替。

于 2011-01-25T23:43:38.883 回答
2

如果您没有另外指定,我相信 C 编译器只会猜测未声明的函数采用extern int foo(). 这就是为什么atoi有效而atof无效。您使用了哪些编译器标志?我建议使用-Wall打开一堆 gcc 警告,其中应该包括引用未声明的函数。

于 2011-01-25T23:41:21.187 回答
2

C 允许您在没有声明该函数的情况下调用函数。

该函数将被假定返回一个int并且参数将使用默认促销传递。如果这些与函数实际期望的不匹配,您将获得未定义的行为。

编译器通常会针对这种情况发出警告,但并非总是如此(这也取决于编译器配置)。

于 2011-01-25T23:42:27.050 回答
1

在 C 中,当您使用未声明的函数时,它假定它具有默认原型:

int FUNCTION_NAME();

请注意,在 C 中使用 () 作为原型意味着它接受任何参数。

如果您使用标志 -Wall 进行编译(我建议您始终使用此标志,因为它会启用所有推荐的警告),您将收到一个警告(不是错误),告诉您您正在使用未声明的函数。

于 2011-01-25T23:45:18.070 回答
0

不幸的是,C 不需要在使用之前对函数进行原型化(甚至声明)——但是如果没有原型,它会自动对函数做出某些假设。其中之一是它返回一个int。在您的情况下,atoi确实返回一个int,因此它可以正常工作。atof没有,所以它不能正常工作。缺少原型/声明,你会得到未定义的行为——通常它最终会检索发生在int通常返回的寄存器中的任何值,并使用它。看来,在您的特定情况下,这恰好是零,但它也可能很容易成为其他东西。

这是许多人推动“C++ 作为更好的 C”的原因之一——C++ 确实要求在使用之前声明所有函数,并且还需要指定所有(非可变参数)参数的类型(即 C++函数声明类似于 C 原型,而不是 C 声明)。

于 2011-01-25T23:45:26.690 回答