简体   繁体   English

为什么 `printf` function 没有被定义时 gcc 不抛出错误?

[英]Why doesn't gcc throw an error when the `printf` function hasn't been defined?

The context上下文

Consider the following file考虑以下文件

$ cat main.c
int main() {
  printf("%d", 10);
  return 0;
}

If we stop the compiler after the preprocessor stage, we get如果我们在预处理器阶段之后停止编译器,我们会得到

$ gcc -E main.c
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "main.c"
int main() {
  printf("%d", 10);
  return 0;
}

As seen above, the printf function is not defined.如上所示, printf function。 However, gcc dooesn't throw a compilation error (see below) when we try to compile the source file shown above但是,当我们尝试编译上面显示的源文件时, gcc抛出编译错误(见下文)

$ gcc main.c 2>/dev/null && echo $?
0

Additional context附加上下文

I know that gcc warns about this我知道gcc发出警告

$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:2:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
    2 |   printf("%d", 10);
      |   ^~~~~~
main.c:2:3: warning: incompatible implicit declaration of built-in function ‘printf’
main.c:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
  +++ |+#include <stdio.h>
    1 | int main() {

The questions问题

  1. Why does gcc compile the source file when the printf function hasn't been defined?为什么gccprintf function没有定义的情况下编译源文件? Are there files that gcc includes in every file by default? gcc是否默认包含在每个文件中的文件?
  2. Assuming that gcc , by default, includes some header files in every file.假设gcc默认情况下在每个文件中包含一些 header 文件。 Is there any way to disable this behavior so that when a function (such as printf ) is not found in the preprocessor output, an error is thrown instead of a warning?有什么方法可以禁用此行为,以便在预处理器 output 中找不到 function(例如printf )时,抛出错误而不是警告?

Indeed, attempting to call the function without a declaration is a constraint violation and thus requires a diagnostic (warning or error) per the C language spec.事实上,尝试在没有声明的情况下调用 function 是违反约束的,因此需要根据 C 语言规范进行诊断(警告或错误)。 But a diagnostic is not required to be fatal, and the compiler is permitted to do whatever it likes if it proceeds.但是诊断不需要是致命的,如果继续,编译器可以为所欲为。

For historical reasons, "implicit function declarations" are allowed by GCC by default;由于历史原因,GCC默认允许“隐式function声明”; you can change this with -Werror=implicit-function-declaration .您可以使用-Werror=implicit-function-declaration更改它。 However, it's not practical to fix this default or even use this default yourself, thanks to autoconf brokenness: a huge number of autoconf tests probe for existence of functions using test programs that intentionally (for utterly wrong reasons, not even historically valid ones) omit the declaration.然而,修复这个默认值甚至自己使用这个默认值是不切实际的,这要归功于 autoconf 的缺陷:大量的 autoconf 测试使用故意(出于完全错误的原因,甚至不是历史上有效的原因)忽略的测试程序来探测函数的存在声明。 So if you changed the default here, autoconf as used in lots of applications would suddenly decide none of the functions it's probing for exist.因此,如果您在此处更改默认值,许多应用程序中使用的 autoconf 会突然决定它正在探测的功能都不存在。

Why does gcc compile the source file when the printf function hasn't been defined?为什么gcc在printf function没有定义的情况下编译源文件?

To be just a bit pedantic, printf isn't declared .有点迂腐, printf声明 The definition of printf -- the object code -- is in the C standard library. printf 的定义——object 代码——在 C 标准库中。

The declaration you're looking for is probably a function prototype .您正在寻找的声明可能是function prototype That declares not only the function's name, but its return type and parameters.这不仅声明了函数的名称,还声明了它的返回类型和参数。

When C was invented and first standardized, there were no function prototypes.当 C 被发明并首次标准化时,还没有 function 原型。 Machines were small and men were men.机器很小,人就是人。 You were expected to call your functions correctly, and you did.你应该正确地调用你的函数,你做到了。 You didn't want to waste time waiting for the compiler to verify what you obviously were doing correctly.您不想浪费时间等待编译器验证您显然在做正确的事情。

It didn't always work out that way, sadly.遗憾的是,事情并不总是这样。 When C was young, on many systems the only memory was real memory, some of which was mapped to the video display.当 C 还年轻时,在许多系统上只有 memory 是真实的 memory,其中一些映射到视频显示。 Our home-grown display manager had functions to display and clear dialogs, and/or the whole screen.我们自己开发的显示管理器具有显示和清除对话框和/或整个屏幕的功能。 Different functions written by different people at different times chose a different order for the {address, length} pair of parameters for these functions.不同人在不同时间编写的不同函数为这些函数的 {address, length} 对参数选择了不同的顺序。 The first sign that you'd called one using the wrong argument order was the display being corrupted, at which point often the only recovery was the power switch.您使用错误的参数顺序调用的第一个迹象是显示被损坏,此时唯一的恢复通常是电源开关。

Function prototypes would have helped.... Function 原型会有所帮助....

If your compiler is compiling according to that first standard, C89, your code is absolutely correct.如果您的编译器是根据第一个标准 C89 编译的,那么您的代码绝对正确。 Later versions of the C standard made function prototypes advisable and then mandatory. C 标准的更高版本使 function 原型成为可取的,然后是强制性的。 You asked about gcc;你问的是gcc; have a look at the -std command-line option.查看-std命令行选项。

Are there files that gcc includes in every file by default? gcc是否默认包含在每个文件中的文件?

Not so as you'd notice.不像你会注意到的那样。 If you're using a function from the C standard library, you'll want to include the header file that goes with it.如果您使用的是 C 标准库中的 function,则需要包含随附的 header 文件。 The man page always says which one that is.手册页总是说那是哪一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM