Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could my code compile correctly without necessary headers?

Tags:

c

linux

I use the functions fork(),exec()...

But how can this program be compiled without including some extra headers (like sys/types.h, sys/wait.h).

I use ubuntu 10.04 with gcc version 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;
}
like image 389
ZhengZhiren Avatar asked May 17 '10 09:05

ZhengZhiren


3 Answers

In classic "ANSI" C, if you call a function without declaring it the compiler behaves as if the function was implicitly declared to take a fixed-but-unspecified number of arguments and return int. So your code acts as if fork() and execvp() were declared thus:

int fork();
int execvp();

Since execvp() takes a fixed number of arguments and returns int, this declaration is compatible. fork() also takes a fixed number of arguments, but returns pid_t; however since pid_t and int are equivalent types on most Linux architectures, this declaration is effectively compatible too.

The actual definitions of these functions are in the C standard library, which is linked by default, so the definition is available at link time and thus the code works.

As Keith Thompson notes, this language feature was dropped in the C99 revision of the C language standard, and compilers invoked in C99 or C11 mode must at least issue a warning when a function is called without being explicitly declared.

like image 121
caf Avatar answered Nov 16 '22 01:11

caf


exec and fork are declared in unistd.h, which is most likely included in one if stdio.h or stdlib.h which you explicitly specified in your code. "wait" is from sys/wait.h though... Try invoking gcc with -c -E to generate a preprocessed output and see where the functions' declarations come from.

like image 21
bobah Avatar answered Nov 16 '22 00:11

bobah


caf's answer is only partially correct.

Under the rules specified by the C89/C90 standard (commonly called "ANSI C"), a call to a function with no visible declaration is legal. The compiler assumes that the function returns an int result and takes arguments of the (promoted) type(s) given in the call. If the call is not consistent with the function definition, the behavior is undefined. For such a call, it's entirely the programmer's responsibility to get the call right; the compiler likely will not tell you if you make a mistake.

The 1999 ISO C standard dropped this "implicit int" rule, and made a call to an undeclared function a constraint violation, requiring a diagnostic. (The diagnostic may be a non-fatal warning, or it can cause compilation to fail.) Once the diagnostic has been printed, if the compiler creates an executable, its behavior is undefined.

Unfortunately, many compilers still don't enforce modern C rules by default. Most of them can be made to do so with appropriate compile-time options.

For gcc in particular, you can compile with

gcc -std=c99 -pedantic

or

gcc -std=c11 -pedantic

(The latter didn't exist yet when caf's answer was written.) Or, if you also want to use gcc-specific extensions, you can use -std=gnu99 or -std=gnu11. The default is currently -std=gnu89. This will likely be changed to -std=gnu11 in a future release of gcc.

gcc-compatible compilers like clang will generally follow the same rules. For other compilers, you'll have to consult their documentation to find out how to persuade them to enforce modern C rules. (Microsoft's C compiler has very incomplete support for standards later than C90.)

like image 36
Keith Thompson Avatar answered Nov 16 '22 00:11

Keith Thompson