2012-07-15 89 views
2

此代码会导致编译错误 “错误: 'P' 与不同类型的重定义”:为什么此代码会导致编译错误“重新定义”?

void fun() { 
    printf("fun"); 
} 
void (*p)(); 
p = &fun; 

但是,如果修改
void (*p)(); p = &fun;
void (*p)() = &fun,一切都OK了。

什么
void (*p)(); p = &fun;
void (*p)() = &fun之间的区别?

+1

[定义和分配指向全局和局部范围函数的指针]可能的副本(http://stackoverflow.com/questions/5962358/definition-and-assignment-of-pointers-to-functions-at-global和本地范围) – 2012-07-15 14:38:38

+0

您是否正在编译所有警告和严格的ANSI模式(应该是这样)? – 2012-07-15 14:39:31

回答

1

三个前回答不回答这个问题,是不正确的,当他们表明,“P = &fun;”是一项任务。

实际上,所述编译器试图解释“P = &fun;”作为声明,所以“p”是一个说明符,“&乐趣”是一个初始化方法,和“p = &乐趣”形成一个init说明符(在C规范的形式语法中)。

将此解释为声明后,应该在声明中的类型默认为int(因为遗留原因),因此编译器实质上将此视为“int p = &fun;”,它是p的定义。因为p先前被定义为指向函数的指针,编译器会抱怨你正在用不同的类型重新定义p。

对于语言语法学家:我无法弄清楚这可能是如何在形式语法中作出声明。一个翻译单元将扩展到一个外部声明,一个外部声明将扩展到一个声明,并且一个声明将扩展为“声明指定符init-declarator-list [opt];”(在C标准中每6.7) 。声明说明符似乎至少需要一个涉及存储类说明符,类型说明符,类型限定符或函数说明符的关键字。源中没有这样的关键字,所以这不能是一个声明。我怀疑编译器是用1999年标准之前的一些语法解析的,所以这是传统行为。尽管如此,错误信息却使编译器清楚地看到了两个定义,而不是一个定义,后面跟着一个赋值。

3

您不能在全局范围内执行任意赋值;请尝试:

void fun() { 
    printf("fun"); 
} 

void (*p)(); 

int main(void) { 
p = &fun; 
return 0; 
} 

void (*p)() = &fun;因为您正在创建和初始化变量而工作。全球范围内允许初始化。 void (*p)(); p = &fun;创建一个未初始化的变量,然后为其分配值。分配的处理与初始化不同,需要在某个函数内执行。

2
void (*p)(); // This is a declaration 

void (*p)() = &fun; // This is also a declaration 

的声明。

p = &fun; // This is a statement 

是一个声明。声明不是声明(声明不是声明)。

你不能在文件范围有语句。 C只允许在块范围内有语句。

2

只有声明和函数定义在全局范围内有效;任务不是。

区别在于int n = 1;是一个带初始化的声明,而n = 1;是一个赋值。前者在全球范围内是有效的,而后者则不是。函数指针也是如此。

作为一项规则,你应该总是喜欢初始化任务,并能解决你的问题:

void fun() { /* ... */ } 

void (*p)() = &fun; // declaration, definition and initialization of "p" 
相关问题