5

If "a function" were compiled separately, the mismatch would not be detected, "the function" would return a double that main would treat as an int... In the light of what we have said about how declarations must match definitions this might seems surprising. The reason a mismatch can happen is that if there is no function prototype, a function is implicitly declared by its first appearance in an expression, such as

    sum += "the function"(line);

If a name that has not been previously declared occurs in an expression and is followed by a left parenthesis, it is declared by context to be a function name, the function is assumed to return an int, and nothing is assumed about its arguments.

I apologize beforehand for the ambiguous question, but what does this mean?

By the way this is page 73 chapter 4.3 from Brian W. Kernighan and Dennis M. Ritchie's C Programming Language book, 2nd edition.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Matthew Hoggan
  • 7,402
  • 16
  • 75
  • 140
  • What page is this in K&R? But I think the question you're asking is about default-ints where you declare functions/types, and they default to `int`. This thread is I think a duplicate of your question: http://stackoverflow.com/questions/5885156/no-defined-type-of-a-function-parameter-defaults-to-int-am-i-insane – wkl Nov 22 '11 at 00:32

3 Answers3

14

K&R2 covers the 1989/1990 version of the language. Later editions of the ISO C standard (1999, 2011, etc.), drop the "implicit int" rule, and requires a visible declaration for any function you call. Compilers don't necessarily enforce this by default, but you should be able to request more stringent warnings -- and you definitely should. In well-written new code, the rule is irrelevant (but it is necessary to understand it).

An example: the standard sqrt() function is declared in <math.h>:

double sqrt(double);

If you write a call without the required #include <math.h>:

double x = 64.0;
double y = sqrt(x);

a C90 compiler will assume that sqrt returns int -- and it will generate code to convert the result from int to double. The result will be garbage, or perhaps a crash.

(You could manually declare sqrt yourself, but that's the wrong solution.)

So don't do that. Always include whatever header is required for any function you call. You might get away with calling an undeclared function if it does return int (and if your compiler doesn't enforce strict C99 or C11 semantics, and if a few other conditions are satisfied), but there's no good reason to do so.

Understanding the "implicit int" rule is still useful for understanding the behavior of old or poorly written code, but you should never depend on it in new code.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
7

Function prototypes were introduced into the language late.

Before prototypes, the compiler would assume that every argument passed to every unknown function should be passed as an integer and would assume that the return value was also an integer.

This worked fine for the few cases where it was correct, but meant people had to write programs in an awkward order so that functions would never rely on unknown functions that did not match this expectation.

When prototypes were introduced into C89 (aka ANSI C or ISO C), the prototypes allow the compiler to know exactly what types of arguments are expected and what types of results will be returned.

It is strongly recommended that you use function prototypes for all new code; when working on an entirely old code base, the prototypes might be harmful. (Or, if the code must be compilable on a pre-ANSI C compiler, then you might wish to leave off the prototypes so it can be built on the ancient software. gcc is the only place I've seen this in a long time.)

sarnold
  • 102,305
  • 22
  • 181
  • 238
0

It's just stating that if the compiler comes across code that calls an unknown function, then it implicitly treats it as if it had already seen a declared prototype of the form int unknown();

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
TJD
  • 11,800
  • 1
  • 26
  • 34
  • @TJD: What is the significane of this, and when might one come accross this? Could you provide an example? – Matthew Hoggan Nov 22 '11 at 00:36
  • The text reads "... and nothing is assumed about its arguments.", but `(void)` means "takes no arguments". That's different from `()`. – R. Martinho Fernandes Nov 22 '11 at 00:38
  • Yeah, say you have file 1 that contains a call such as x = foo();, but you didn't include the header file that declares type formats for foo, and foo is implemented in file 2. When the compiler generates the assembly code for file 1, it has to make an assumption about how to generate the calling code for foo and handling return params. The assumption it chooses is 1) do nothing with input args and 2) return type is int – TJD Nov 22 '11 at 00:40
  • also, most compilers will generate a warning in this case, to let you know it is doing some guesswork that might be unintended – TJD Nov 22 '11 at 00:41
  • No, it doesn't choose to do nothing with the arguments. It passes them to the function. – R. Martinho Fernandes Nov 22 '11 at 00:41
  • @R. Martinho, that's true, it passes them. But it doesn't make any type assumptions, so uses the local type info of the args without casting, (which may or may not match the actual function implementation) – TJD Nov 22 '11 at 00:45
  • @TJD: "it [...] uses the local type info of the args without casting" is not exactly right IMHO. There are some implicit type promotions that happen when you pass arguments to an unprototyped function; for example, expressions of types `char` and `short` get converted to `int`s, and expressions of types `float` get converted to `double`s. Obviously the compiler can only do this based on the types in the caller, not the types in the actual function implementation, but even so, I would consider it to be "casting". – ruakh Nov 22 '11 at 01:32