C 如果没有必要的头,我的代码如何正确编译?

C 如果没有必要的头,我的代码如何正确编译?,c,linux,C,Linux,我使用函数fork,exec 但是,如何在不包含诸如sys/types.h、sys/wait.h之类的额外头的情况下编译这个程序呢 我使用Ubuntu10.04和gcc版本4.4.3 #include <stdio.h> #include <stdlib.h> int main() { pid_t pid; printf("before fork\n"); pid = fork(); if(pid == 0) { /*child*/ if(exe

我使用函数fork,exec

但是,如何在不包含诸如sys/types.h、sys/wait.h之类的额外头的情况下编译这个程序呢

我使用Ubuntu10.04和gcc版本4.4.3

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

int main()
{
 pid_t pid;

 printf("before fork\n");

 pid = fork();

 if(pid == 0)
 {
  /*child*/
  if(execvp("./cpuid", NULL))
  {
   printf("error\n");
   exit(0);
  }
 }
 else
 {
  if(wait(NULL) != -1)
  {
   printf("ok\n");
  }
 }

 return 0;
}

exec和fork在unistd.h中声明,它很可能包含在代码中明确指定的if stdio.h或stdlib.h中。wait来自sys/wait.h,但。。。尝试使用-c-E调用gcc来生成预处理的输出,并查看函数声明的来源。

在经典的ANSI c中,如果调用一个函数而不声明它,编译器的行为就好像隐式声明该函数接受固定但未指定数量的参数并返回int。因此,代码的行为就好像fork和execvp是这样声明的:

int fork();
int execvp();
由于execvp接受固定数量的参数并返回int,因此此声明是兼容的。fork还接受固定数量的参数,但返回pid\u t;然而,由于pid_t和int在大多数Linux体系结构上是等效的类型,因此该声明也可以有效地兼容

这些函数的实际定义在C标准库中,默认情况下是链接的,因此该定义在链接时可用,因此代码可以工作

正如Keith Thompson所指出的,在C语言标准的C99版本中删除了此语言功能,在C99或C11模式下调用的编译器在调用函数时必须至少发出警告,而没有显式声明。

仅部分正确

根据C89/C90标准(通常称为ANSI C)规定的规则,调用没有可见声明的函数是合法的。编译器假定函数返回int结果,并获取调用中给定的提升类型的参数。如果调用与函数定义不一致,则行为未定义。对于这样的调用,完全由程序员负责正确调用;如果您出错,编译器可能不会告诉您

1999年的ISO C标准放弃了这个隐式int规则,并将对未声明函数的调用视为违反约束,需要进行诊断。诊断可能是非致命警告,也可能导致编译失败。打印诊断后,如果编译器创建可执行文件,则其行为未定义

不幸的是,默认情况下,许多编译器仍然没有强制执行现代C规则。大多数都可以通过适当的编译时选项来实现

特别是对于gcc,您可以使用

gcc -std=c99 -pedantic

当caf的答案被写出来时,后者还不存在。或者,如果您还想使用特定于gcc的扩展,可以使用-std=gnu99或-std=gnu11。默认值当前为-std=gnu89。在gcc的未来版本中,这可能会更改为-std=gnu11


与gcc兼容的编译器(如clang)通常遵循相同的规则。对于其他编译器,您必须查阅他们的文档,了解如何说服他们执行现代C规则。Microsoft的C编译器对C90之后的标准的支持非常不完整。

此外,如果指定标准c89或c99而不是默认的gcc行为,则会出现错误。我以前没有使用-E选项,感谢您的建议。非常感谢。你的回答很有帮助。而且,这是gcc行为吗?那么标准c呢?它是标准c行为;但是,如果没有其他原因阻止您使用原型声明函数,这意味着编译器无法检查参数的数量和类型是否正确,则编写依赖于它的程序被视为不正确的做法;看到我刚刚发布的新答案了吗。
gcc -std=c11 -pedantic