此代码导致编译错误“错误:使用不同类型重新定义'p'”:
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
但如果修改
void (*p)(); p = &fun;
到
void (*p)() = &fun
,一切都很好。
有什么区别
void (*p)(); p = &fun;
和
void (*p)() = &fun
?
答案 0 :(得分:3)
您无法在全局范围内执行任意分配;尝试:
void fun() {
printf("fun");
}
void (*p)();
int main(void) {
p = &fun;
return 0;
}
void (*p)() = &fun;
有效,因为您正在创建和初始化变量。全局范围内允许初始化。 void (*p)(); p = &fun;
创建一个未初始化的变量,然后为其分配值。分配与初始化的处理方式不同,需要在某个函数内部执行。
答案 1 :(得分:2)
void (*p)(); // This is a declaration
和
void (*p)() = &fun; // This is also a declaration
是声明。
p = &fun; // This is a statement
是一份声明。声明不是声明(声明不是声明)。
您不能在文件范围内拥有语句。 C只允许在块范围内使用语句。
答案 2 :(得分:2)
只有声明和函数定义在全局范围内有效;作业不是。
不同之处在于int n = 1;
是一个初始化声明,而n = 1;
是一个赋值。前者在全球范围内有效,而后者则不然。函数指针也是如此。
作为一项规则,您应该始终更喜欢初始化到分配,这可以解决您的问题:
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"
答案 3 :(得分:1)
之前的三个答案没有回答问题,并且当他们表示“p =& fun;”是一项任务时不正确。
实际上,编译器试图将“p =& fun;”解释为声明,因此“p”是声明符,“& fun”是初始化器,“p =& fun”形成一个init-declarator(在C规范的正式语法中)。
将此解释为声明后,声明中应该出现的类型默认为int(由于遗留原因),因此编译器基本上将其视为“int p =& fun;”,这是p的定义。因为p以前被定义为函数的指针,所以编译器抱怨你用另一种类型重新定义了p。
对于语言语法学家:我无法弄清楚这可能是正式语法中的声明。翻译单元将扩展为外部声明,外部声明将扩展为声明,声明将扩展为“declaration-specifiers init-declarator-list [opt];”(C标准中的6.7) 。声明说明符似乎至少需要存储类说明符,类型说明符,类型限定符或函数说明符中涉及的一个关键字。源中没有出现这样的关键字,因此这不是声明。我怀疑编译器正在使用1999标准之前的一些语法进行解析,因此这是遗留行为。尽管如此,错误消息清楚地表明编译器已经看到了两个定义,而不是一个定义后跟一个赋值。