Not including stdlib.h does not produce any compiler error!
Asked Answered
A

5

4

Hopefully this is a very simple question. Following is the C pgm (test.c) I have.

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

Note that I am using atoi() and atof() from stdlib.h, but I do not include that header file. I compile the pgm (gcc test.c) and get no compiler error!

I run the pgm (./a.out) and here is the output, which is wrong.

The intValue is 1 and the doubleValue is 0

Now I include stdlib.h (by removing the comments before the #include) and recompile it and run it again. This time I get the right output:

The intValue is 1 and the doubleValue is 2

How come the compiler did not complain about not including the stdlib.h and still let me use the atoi(), atof() functions?

My gcc info:

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

Any thoughts appreciated!

Amar answered 25/1, 2011 at 23:38 Comment(7)
Always turn on warnings when using GCC (-Wall please!)Densify
C++ doesn't specify which standard library header might include which others. Does C? (If not, <stdio.h> meight very well include <stdlib.h>.)Addictive
C, unlike C++, requires that all standard headers behave as-if they do not include each other.Songful
@Zack: Thanks for clarifying that! I really didn't know.Addictive
I'd suggest -Werror to go with -Wall, otherwise you won't notice when a new warning appears.Neiman
In principle -Werror is nice, in practice it causes your build to blow up when somebody tries to compile under slightly different conditions and the uninitialized-variable false positive set changes. :-(Songful
Possible duplicate of Why #include <stdio.h> is *not* required to use printf()?Mohan
S
13

For historical reasons -- specifically, compatibility with very old C programs (pre-C89) -- using a function without having declared it first only provokes a warning from GCC, not an error. But the return type of such a function is assumed to be int, not double, which is why the program executes incorrectly.

If you use -Wall on the command line, you get a diagnostic:

$ 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’

You should use -Wall basically always. Other very useful warning options for new code are -Wextra, -Wstrict-prototypes, -Wmissing-prototypes, -pedantic, and -Wwrite-strings, but compared to -Wall they have much higher false positive rates.

Tangentially: never use atoi nor atof, they hide input errors. Use strtol and strtod instead.

Songful answered 25/1, 2011 at 23:43 Comment(2)
Side note: Wwrite-strings is on by default for C++ code. It's off by default for C because most C code is still C89 (sigh), and C89 does not have const.Densify
C89 does have const; it was "traditional" C that didn't have it. But C (even in the very latest draft standard, AFAIK) defines the type of string constants to be char *, unlike C++. -Wwrite-strings brings C in line with C++. I participated in the project to turn on -Wwrite-strings when compiling GCC itself; it was on the order of one man-year of work to flush out a tiny number of bugs. I can't really blame the committee for leaving this backward compatibility wart alone.Songful
F
2

If you don't specify otherwise, I believe a C compiler will just guess that undeclared functions take the form extern int foo(). Which is why atoi works and atof doesn't. Which compiler flags were you using? I suggest using -Wall to turn on a bunch of gcc warnings, which should include referencing undeclared functions.

Forwardness answered 25/1, 2011 at 23:41 Comment(0)
H
2

C allows you to call a function without having a declaration for that function.

The function will be assumed to return an int and arguments will be passed using default promotions. If those don't match what the function actually expects, you'll get undefined behavior.

Compilers will often warn for this case, but not always (and that will also depend on compiler configuration).

Horseshoes answered 25/1, 2011 at 23:42 Comment(1)
If atoi() is passed a char* then even without a prototype it will not be undefined behavior.Horseshoes
N
1

In C, when you use a function that was not declared, it assumes that it has the default prototype:

int FUNCTION_NAME();

Note that in C using () as prototype means it accepts any arguments.

If you compile with the flag -Wall (I recommend you to always use this flag, since it enables all recommended warnings) you will get a warning (not an error) telling you that you are using an undeclared function.

Noodle answered 25/1, 2011 at 23:45 Comment(0)
I
0

C, unfortunately, does not require functions to be prototyped (or even declared) before use -- but without a prototype, it automatically makes certain assumptions about the function. One of those is that it returns an int. In your case, atoi does return an int, so it works correctly. atof doesn't, so it doesn't work correctly. Lacking a prototype/declaration, you get undefined behavior -- typically it'll end up retrieving whatever value happens to be in the register where an int would normally be returned, and using that. It appears that in your particular case, that happens to be a zero, but it could just as easily be something else.

This is one of the reasons many people push "C++ as a better C" -- C++ does require that all functions be declared before use, and further that you specify the types of all (non-variadic) parameters as well (i.e. a C++ function declaration is like a C prototype, not like a C declaration).

Ilysa answered 25/1, 2011 at 23:45 Comment(2)
Is it undefined behaviour even in the case with atoi?Managua
@Giorgi: No. If the function matches the assumptions the compiler makes, it's fine. It's just when there's a mismatch (such as with atof) that you get undefined behavior.Ilysa

© 2022 - 2024 — McMap. All rights reserved.