为什么此代码会导致编译错误“重新定义”?
此代码会导致编译错误 “错误: 'P' 与不同类型的重定义”:为什么此代码会导致编译错误“重新定义”?
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
但是,如果修改void (*p)(); p = &fun;
到void (*p)() = &fun
,一切都OK了。
什么void (*p)(); p = &fun;
和void (*p)() = &fun
之间的区别?
三个前回答不回答这个问题,是不正确的,当他们表明,“P = &fun;”是一项任务。
实际上,所述编译器试图解释“P = &fun;”作为声明,所以“p”是一个说明符,“&乐趣”是一个初始化方法,和“p = &乐趣”形成一个init说明符(在C规范的形式语法中)。
将此解释为声明后,应该在声明中的类型默认为int(因为遗留原因),因此编译器实质上将此视为“int p = &fun;”,它是p的定义。因为p先前被定义为指向函数的指针,编译器会抱怨你正在用不同的类型重新定义p。
对于语言语法学家:我无法弄清楚这可能是如何在形式语法中作出声明。一个翻译单元将扩展到一个外部声明,一个外部声明将扩展到一个声明,并且一个声明将扩展为“声明指定符init-declarator-list [opt];”(在C标准中每6.7) 。声明说明符似乎至少需要一个涉及存储类说明符,类型说明符,类型限定符或函数说明符的关键字。源中没有这样的关键字,所以这不能是一个声明。我怀疑编译器是用1999年标准之前的一些语法解析的,所以这是传统行为。尽管如此,错误信息却使编译器清楚地看到了两个定义,而不是一个定义,后面跟着一个赋值。
您不能在全局范围内执行任意赋值;请尝试:
void fun() {
printf("fun");
}
void (*p)();
int main(void) {
p = &fun;
return 0;
}
void (*p)() = &fun;
因为您正在创建和初始化变量而工作。全球范围内允许初始化。 void (*p)(); p = &fun;
创建一个未初始化的变量,然后为其分配值。分配的处理与初始化不同,需要在某个函数内执行。
void (*p)(); // This is a declaration
和
void (*p)() = &fun; // This is also a declaration
的声明。
p = &fun; // This is a statement
是一个声明。声明不是声明(声明不是声明)。
你不能在文件范围有语句。 C只允许在块范围内有语句。
只有声明和函数定义在全局范围内有效;任务不是。
区别在于int n = 1;
是一个带初始化的声明,而n = 1;
是一个赋值。前者在全球范围内是有效的,而后者则不是。函数指针也是如此。
作为一项规则,你应该总是喜欢初始化任务,并能解决你的问题:
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"
[定义和分配指向全局和局部范围函数的指针]可能的副本(http://stackoverflow.com/questions/5962358/definition-and-assignment-of-pointers-to-functions-at-global和本地范围) – 2012-07-15 14:38:38
您是否正在编译所有警告和严格的ANSI模式(应该是这样)? – 2012-07-15 14:39:31