Consider the following C program:
int f() { return 9; }
int main() {
int (*h1)(int);
h1 = f; // why is this allowed?
return h1(7);
}
According to the C11 Standard, Sec. 6.5.16.1, in a simple assignment, "one of the following shall hold", and the only relevant one in the list is the following:
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
Moreover, this is a "constraint", meaning, a conforming implementation must report a diagnostic message if it is violated.
It seems to me that this constraint is violated in the assignment in the program above. Both sides of the assignment are function pointers. So the question is, are the two function types compatible? This is answered in Sec. 6.7.6.3:
For two function types to be compatible, both shall specify compatible return types.146) 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. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier.
In this case, one of the types, that of h1, has a parameter type list; the other, f, does not. Hence the last sentence in the quote above applies: in particular, "both shall agree in the number of parameters". Clearly h1 takes one parameter. What about f? The following point occurs just before the above:
An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
So clearly f takes 0 parameters. So the two types do not agree in the number of parameters, the two function types are incompatible, and the assignment violates a constraint, and a diagnostic should be issued.
However, both gcc 4.8 and Clang emit no warnings when compiling the program:
tmp$ gcc-mp-4.8 -std=c11 -Wall tmp4.c
tmp$ cc -std=c11 -Wall tmp4.c
tmp$
By the way, both compilers do issue warnings if f is declared "int f(void) ...", but this should not be necessary based on my reading of the Standard above.
The questions:
Q1: Does the assignment "h1=f;" in the program above violate the constraint "both operands are pointers to qualified or unqualified versions of compatible types"? Specifically:
Q2: The type of h1 in the expression "h1=f" is pointer-to-T1 for some function type T1. What exactly is T1?
Q3: The type of f in the expression "h1=f" is pointer-to-T2 for some function type T2. What exactly is T2?
Q4: Are T1 and T2 compatible types? (Please quote appropriate sections of the Standard or other documents to support the answer.)
Q1', Q2', Q3', Q4': Now suppose the declaration of f is changed to "int f(void) { return 9; }". Answer questions 1-4 again for this program.