user805627
user805627

Reputation: 4417

Why does this code cause compilation error "redefinition"?

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

Answers (4)

Eric Postpischil
Eric Postpischil

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

slartibartfast
slartibartfast

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

Kerrek SB
Kerrek SB

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

ouah
ouah

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

Related Questions