C 2011 (N1570) 6.7.6.3 15:
For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions.… [Emphasis added.]
char
is promoted to int
, so char a
is not compatible with an empty list. int a
would be; int foo(); int foo(int a);
is allowed.
Essentially, the reason for this is that, if you declare a function int foo()
and then call it, say with int foo(3)
, the compiler has to know what to pass it. The rules, derived from history, are to perform the default argument promotions. So int foo(3)
gets called as if it were int foo(int)
.
Then, if you later define the function with int foo(char)
, the definition will not match the call. In many C implementations a char
and an int
may be put in the same place for calling a function, but a C implementation could do something different. A float
and a double
would be a greater conflict.