How could my code compile correctly without necessary headers? - c

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;
}

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.

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.

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.)

Related

How to understand "main function's prototype cannot be supplied by the program"?

I read main function, and came across following words:
The main function has several special properties:
A prototype for this function cannot be supplied by the program.
Then I wrote a simple program:
# cat foo.c
int main(void);
int main(void)
{
return 0;
}
And compiled it:
# gcc -Wall -Wextra -Wpedantic -Werror foo.c
#
All seems OK! So I am little confused about how to understand "A prototype for this function cannot be supplied by the program". Anyone can give some insights?
The C standard (5.1.2.2.1) just says that the compiler (for hosted systems like PC etc) will not provide a prototype for the main function. So cppreference.com isn't really correct, the C standard doesn't prohibit the application programmer from writing a prototype, although doing so is probably meaningless practice in hosted systems.
In freestanding systems (embedded systems etc), it might be meaningful to declare a prototype for main in case it needs to be called from a reset ISR or from the "C runtime" (CRT).
What's important to realize no matter system is that the compiler specifies which forms of main that are valid. Never the programmer.
main function parameters and the return value is defined by the standard. You shall not provide your own one. But the compiler may accept and compile even non standard types of main.
On the other hand, the main function will not be called by your code so your prototype is not needed at all.

strtoull() Availbility in C89

I have been reading through the documentation for strtoul()/strtoull() from here, and under the "Conforming To" section towards to bottom, it makes these two points:
strtoul(): POSIX.1-2001, POSIX.1-2008, C89, C99 SVr4.
strtoull(): POSIX.1-2001, POSIX.1-2008, C99.
These two lines, in addition to other references throughout the document indicate to me that the function strtoull should not be available when compiling a program using the c89/c90 standard. However, when I run a quick test with gcc, it allows me to call this function, regardless of the standard that I specify.
First, the code I am using to test:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned long long x;
const char *str = "1234";
x = strtoull(str, NULL, 10);
printf("%llu\n", x);
return 0;
}
And here is my compilation command:
gcc test.c -std=c89 -pedantic -Wall -Wextra
Now, in fairness it does warn me of the compatibility issue:
test.c: In function ‘main’:
test.c:6:16: warning: ISO C90 does not support ‘long long’ [-Wlong-long]
unsigned long long x;
^~~~
test.c:9:6: warning: implicit declaration of function ‘strtoull’; did you mean ‘strtoul’? [-Wimplicit-function-declaration]
x = strtoull(str, NULL, 10);
^~~~~~~~
strtoul
test.c:11:9: warning: ISO C90 does not support the ‘ll’ gnu_printf length modifier [-Wformat=]
printf("%llu\n", x);
^~~~~~~~
These warning messages are exactly what I would expect given the documentation. It notifies me that the function I have specified cannot be found, and even that the C90 standard doesn't support unsigned long long. However, when I attempt to run this code, it works just fine, with no crashing or other types of errors. It prints the value 1234, as desired. So, based on this experiment, I have a few questions that I was hoping someone more seasoned than I could answer.
Is this a matter of me not providing the necessary compilation flags to enforce the 'strict' c98 standard?
Is this a case of me misunderstanding the documentation, or is there some documentation for gcc itself that I should refer to? And, if so, where could I find it?
Is there something fundamental about the compiling/linking process that I am not understanding, which explains this issue?
Why would I be warned of an incompatibility, even warned that the function I am calling does not exist, but the code still works with no issue?
Does this experiment imply that the -std=c89 -pedantic flags do not actually enforce the C89/C90 standard?
As a final note, I am not trying to say I want to use this function in C89, I was just curious about the compatibility restriction, and then confused about the answer.
Thanks in advance for any responses!
From a C89/C90 compiler's point of view, the only thing wrong with your code is the use of unsigned long long which looks like a syntax error. The standard requires only that the compiler produce a "diagnostic" in this case, and GCC has done so with its "ISO C90 does not support long long" warning. There is no requirement that this error should be fatal, and the compiler can decide to handle the code some other way if it wants. GCC obviously chooses to understand it as the long long type which it supports as an extension to C89.
The use of strtoull then just looks like some function that you made up, as C89 had no way of knowing that this name would be special in some future version of the standard. (Well, they did specify that more functions starting with str could be added to <string.h> in the future, but that doesn't make your code illegal for C89.) You haven't declared it, but C89 allowed implicit declarations, so it's understood to be declared as int strtoull();, i.e. returning int and with unspecified arguments. AFAIK no diagnostic was required for implicit declarations, but GCC chooses to issue one anyway. So it's treated like any other call to a function not defined in this source file, and the compiler presumes that some other part of your program (including the libraries you use) will define it.
And in fact some other part of your program does define it, namely libc, since your libc conforms to C99 and later. (You know, hopefully, that libc is not part of GCC.) C library authors generally don't provide a version of the library that only includes functions from a particular standard version, since having so many different libraries around would be awkward and inefficient. So linking succeeds.
Note, though, that because of the implicit declaration, the program may not actually work correctly. The compiler will generate code incorrectly assuming that strtoull returns int, which depending on your system's calling conventions, may cause all sorts of problems. On x86-64, it means that your program will only look at the low 32 bits of the result and will sign-extend them to 64 bits. So if you try to convert a number that fits in 32 bits but would not fit in long long, you'll get the wrong result. Example.
If you want a program that would work on a system that only supports C89 and nothing else, it's your responsibility to look at the diagnostics issued by the compiler and fix the corresponding problems. The -pedantic-errors option mentioned in comments can help with this, as it causes compilation to fail when such diagnostics are issued.
It would also help if you could find a C89-only libc, but that's not GCC's problem. But its implicit declaration warnings do give you some assistance in noticing that you have called a function which you may not have intended for your program to define.
As a final point, it's historically been part of GCC's design philosophy that they don't think "enforcing the standard" is really part of what they want to do. They saw their goal as writing a compiler that helps people write and compile programs that are useful, not a linter that checks for conformance with coding standards; they figured the latter should be a separate project, and not one that they were interested in. As such, they were liberal in providing extensions to the standard language, and not particularly diligent in providing ways for programs to avoid using them. They did provide the -pedantic option but apparently with some reluctance, as you can tell from the derogatory name.

Who detects misspelled function name? Compiler or Linker?

According to C How to Program (Deitel):
Standard library functions like printf and scanf are not part of the C programming language. For example, the compiler cannot find a spelling error in printf or scanf. When the compiler compiles a printf statement, it merely provides space in the object program for a “call” to the library function. But the compiler does not know where the library functions are—the linker does. When the linker runs, it locates the library functions and inserts the proper calls to these library functions in the object program. Now the object program is complete and ready to be executed. For this reason, the linked program is called an executable. If the function name is misspelled, it is the linker which will spot the error, because it will not be able to match the name in the C program with the name of any known function in the libraries.
These statements leave me doubtful because of the existence of header file. These files are included during the preprocessing phase, before the compiling one, and, as I read, there are used by the compiler.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
You are right. If you made a typo in any function name, any modern compiler should complain about it. For example, gcc complains for the following code:
$ cat test.c
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c11 -pedantic-errors test.c
test.c: In function ‘main’:
test.c:3:5: error: implicit declaration of function ‘unknown’ [-Wimplicit-function-declaration]
unknown();
^
However, in pre C99 era of C language, any function whose declaration isn't seen by the compiler, it'll assume the function returns an int. So, if you are compiling in pre-C99 mode then a compiler isn't required to warn about it.
Fortunately, this implicit int rule was removed from the C language since C99 and a compiler is required to issue a diagnostic for it in modern C (>= C99).
But if you provide only a declaration or prototype for the function:
$ cat test.c
int unknown(void); /* function prototype */
int main(void)
{
unknown();
return 0;
}
$ gcc -c -Wall -Wextra -std=c89 -std=c11 test.c
$
(Note: I have used -c flag to just compile without linking; but if you don't use -c then compiling & linking will be done in a single step and the error would still come from the linker).
There's no issue despite the fact, you do not have definition for unknown() anywhere. This is because the compiler assumes unknown() has been defined elsewhere and only when the linker looks to resolve the symbol unknown, it'll complain if it can't find the definition for unknown().
Typically, the header file(s) only provide the necessary declarations or prototypes (I have provided a prototype for unknown directly in the file itself in the above example -- it might as well be done via a header file) and usually not the actual definition. Hence, the author is correct in that sense that the linker is the one that spots the error.
So if I write print instead of printf how can't the compiler see that there is no function declared with that name and throw an error?
The compiler can see that there is no declaration in scope for the identifier designating the function. Most will emit a warning under those circumstances, and some will emit an error, or can be configured to do so.
But that's not the same thing as the compiler detecting that the function doesn't exist. It's the compiler detecting that the function name has not been declared. The compiler will exhibit the same behavior if you spell the function name correctly but do not include a prior declaration for it.
Furthermore, C90 and pre-standardization C permitted calls to functions without any prior declaration. Such calls do not conform to C99 or later, but most compilers still do accept them (usually with a warning) for compatibility purposes.
If it is as the book says, why can I declare function in header files if the compiler doesn't watch them?
The compiler does see them, and does use the declarations. Moreover, it relies on the prototype, if the declaration provides one, to perform appropriate argument and return value conversions when you call the function. Moreover, if you use functions whose argument types are altered by the default argument promotions, then your calls to such functions are non-conforming if no prototype is in scope at the point of the call. Undefined behavior results.

Why doesn’t putchar require a header?

Reading this answer which explains the polyglot program on page not found on Stack Overflow I was surprised to read putchar was used because you don't need any #include to use it. This seems to be the case, although en.cppreference.com reference and www.cplusplus.com reference show putchar as defined in the stdio.h header.
How can a function be used (correctly) without having a declaration in C? Or is putchar something inbuilt in compiler (like sizeof operator)?
In c, you can use any function without a declaration.
The compiler then assumes, that the function has a return type of int. The parameters are passed to the function as given. Since there is no function declaration, the compiler cannot verify, if the parameters are correct.
putchar is not builtin into the compiler.
However, since
The function call putchar(c) shall be equivalent to putc(c,stdout).
it might be defined as a macro, e.g.
#define putchar(c) putc(c, stdout)
In this case, you must include stdio.h to have the correct definition for putchar.
Some compilers do weird, non-standard things such as automatically including various common headers. It is possible that the code was compiled on one such compiler.
Otherwise, in the old obsolete C90 standard, you didn't need to have a function prototype visible: if you had not, the compiler would start to assume that the return type was int. Which doesn't make any sense. This nonsense was removed from the C language with the C99 standard.
So the reason the code compiled, was because you used a crappy compiler. There are no guarantees that the code will compile/link or work as predicted.
For example:
int main ()
{
putchar('a');
}
This compiles with gcc as well as gcc -std=c90. But if you compile it as standard C,
gcc -std=c99 -pedantic-errors
you'll get error: implicit declaration of function 'putchar'.

Cannot interpret compiler warning

My compiler (gcc) throws warnings (not errors!) on the line which declares fp:
int fd = open("filename.dat", O_RDONLY);
FILE* fp = fdopen(fd, "r"); // get a file pointer fp from the file descriptor fd
These are the warnings:
main.c: In function ‘main’:
main.c:606: warning: implicit declaration of function ‘fdopen’
main.c:606: warning: initialization makes pointer from integer without a cast
I do not understand these warnings since the return value of fopen is a FILE*. What is the mistake I am making here?
EDIT: I am including stdio.h (and I am also on Linux).
Short answer: use -std=gnu99 when compiling, the usual standard is non-POSIX and does not have fdopen.
warning: implicit declaration of function ‘fdopen’
Means you have forgot to include the header file which the declaration of fdopen() resides in. Then an implicit declaration by the compiler occurs - and that means the return value of the unknown function will be assumed to be int - thus the second warning. You have to write
#include <stdio.h>
Edit: if you properly include stdio.h, then fdopen() might not be available on the system you're targeting. Are you on Windows? This function is POSIX-only.
Edit 2: Sorry, I really should have perceived this. C99 means the ANSI C99 standard - and standard C doesn't force the concept of file descriptors in order to support non-POSIX systems, so it provides fopen() only. fdopen() is related to file descriptors, so it's POSIX-only, so it's not part of standard C99. If you use the -std=gnu99 switch for GCC, it gets rid of the standard's restrictions and lets in the POSIX and GNU-only extensions, essentially fixing your problem.
#define _XOPEN_SOURCE 600
#include <stdio.h>
This conforms perfectly with strict c99
gcc -std=c99 -pedantic -Wall -Wextra -Werror
You are not including #include <stdio.h> in C the compiler therefore "guesses" the declaration of the function you're trying to call. (Taking the parameters you've based and using int as return value). Usually you don't want such guesses therefore the compiler warns you.
Solution: Add proper #includes.
The fdopen function is not part of the C standard and is not available as part of the standard headers if you compile in standard C mode. So you either need to use -std=gnu99 instead of -std=c99 to compile your source or declare the function yourself.
There's a good explanation for the compiler's diagnostic in #H2CO3's answer, so let's only look on the why of things: if you're using glibc (and you probably are), certain POSIX functions may require specific feature test macros to show up.
In particular, you may need to put the following line:
#define _POSIX_SOURCE
// or #define _XOPEN_SOURCE
before
#include <stdio.h>
Certain compilers (such as gcc) also have command line options to the same effect (all the gnu* standards options in gcc).

Resources