Reputation: 4417
This code causes compilation error " error: redefinition of 'p' with a different type":
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
But if modify
void (*p)(); p = &fun;
to
void (*p)() = &fun
, everything is OK.
What's the difference between
void (*p)(); p = &fun;
and
void (*p)() = &fun
?
Upvotes: 2
Views: 873
Reputation: 222486
The three prior answers do not answer the question and are incorrect when they indicate that “p = &fun;” is an assignment.
Actually, the compiler is attempting to interpret “p = &fun;” as a declaration, so “p” is a declarator, “&fun” is an initializer, and “p = &fun” forms an init-declarator (in the formal grammar of the C specification).
Having interpreted this as a declaration, the type that should be in the declaration defaults to int (for legacy reasons), so the compiler essentially sees this as “int p = &fun;”, which is a definition of p. Because p was previously defined as a pointer to a function, the compiler complains that you are redefining p with a different type.
For the language grammarians: I cannot make out how this could be a declaration in the formal grammar. A translation-unit would expand to an external-declaration, an external-declaration would expand to a declaration, and a declaration would expand to “declaration-specifiers init-declarator-list[opt];” (per 6.7 in the C standard). The declaration-specifiers appear to require at least one of the keywords involved in storage-class-specifier, type-specifier, type-qualifier, or function-specifier. No such keyword appears in the source, so this cannot be a declaration. I suspect the compiler is parsing with some grammar from before the 1999 standard, so this is legacy behavior. Nonetheless, the error message makes it clear the compiler has seen two definitions, not a definition followed by an assignment.
Upvotes: 1
Reputation: 4428
You cannot perform arbitrary assignments in the global scope; try:
void fun() {
printf("fun");
}
void (*p)();
int main(void) {
p = &fun;
return 0;
}
void (*p)() = &fun;
works because you're creating and initializing a variable. Initialization is allowed in global scope. void (*p)(); p = &fun;
creates an uninitialized variable and then assigns a value to it. Assigning is treated differently from initializing, and needs to be performed inside some function.
Upvotes: 3
Reputation: 477010
Only declarations and function definitions are valid at the global scope; assignments are not.
The difference is that int n = 1;
is a declaration with initialization, while n = 1;
is an assignment. The former is valid at the global scope, while the latter isn't. The same is true for function pointers.
As a rule, you should always prefer initialization to assignment, and that solves your problem:
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"
Upvotes: 2
Reputation: 145829
void (*p)(); // This is a declaration
and
void (*p)() = &fun; // This is also a declaration
are declarations.
p = &fun; // This is a statement
is a statement. A statement is not a declaration (and a declaration is not a statement).
You cannot have statements at file-scope. C only allows to have statements at block-scope.
Upvotes: 2