undefined functions

So I found a bug (it's probably shouldn't really be "important" but I do include a fix). I know why this bug happens, undefined functions are assumed to return an int, so it chops off the top of a 64 bit pointer.

but why? delving into the standards is tricky. first some terms

  • a function declaration gives the function name and the paramaters. It has a return type, a name and a paramater list. Each of the paramaters is possibly named (C99 6.7.5.3.6 : ...specifies the types of, and may declare identifiers for, the parameters of the function and later, C99 6.9.1 : If the declarator includes a parameter type list, the declaration of each parameter shall include an identifier). It looks like

    int afunction(int aparamater)
    

    .

  • a function prototype is like a weak version of a function declaration. It specifies the return value and the paramaters, but doesn't give the paramater names (C99 6.2.1 : A function prototype is a declaration of a function that declares the types of its parameters). This is used for C++ compatability, I think. It looks like

    int afunction(int)
    

    So you can say a function prototype is always a function declaration, but a function declaration isn't always a prototype.

  • a function definition is where you actually write the function. It looks like

    int afunction(int aparamater) { return aparamater; }
    

    Note that a function definition is also a declaration, which is why you can happily use functions after they are defined in the source code.

Ian Lance Taylor suggested the relevant part of the C99 standard dealing with undefined functions says

6.5.2.2; Paragraph 1 : The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.

The disallows undefined functions by omission; they're not mentioned so they're not allowed. Actually, a little earlier when defining exactly what an expression is (6.5.1.2) we get one definition of a primary expression

An identifier is a primary expression, provided it has been declared as designating an object (in which case it is an lvalue) or a function (in which case it is a function designator)76 76: thus, an undeclared identifier is a violation of the syntax.

An undeclared identifier is not considered a primary expression. What's an expression? Think of it as anything that can go to the right hand side of an = or as the conditional of an if( ) statement.

So, a function declaration is just another type of declarator (C99 6.5.7) which declares an identifier which is the function name (e.g. in the same way int i declares i as being an identifier of integer type, int function(void) declares function() as an identifier of a function that returns int taking no arguments).

Ian Lance Taylor goes on to say

Given traditional C usage, requiring a function declaration can be reasonably viewed as a pedantic requirement, appropriate for -pedantic-errors. In general, if you want gcc to enforce strict adherence to the relevant standard, you must use -pedantic-errors. Of course there is a very reasonable coding style in which functions should always be declared for use. For that coding style, there is -Werror-implicit-function-declaration.

The only problem with this is that no one ever actually turns on those flags, and on 32 bit system (which most of the world use) it doesn't cause an error because the pointer is the same size as an int.