此代码导致编译错误“错误:使用不同类型重新定义'p'”:
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
但如果修改
void (*p)(); p = &fun;
为
void (*p)() = &fun
,一切正常。
void (*p)(); p = &fun;
和有什么区别
void (*p)() = &fun
?
此代码导致编译错误“错误:使用不同类型重新定义'p'”:
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
但如果修改
void (*p)(); p = &fun;
为
void (*p)() = &fun
,一切正常。
void (*p)(); p = &fun;
和有什么区别
void (*p)() = &fun
?
您不能在全局范围内执行任意分配;尝试:
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"
前面的三个答案没有回答问题,并且当它们表明“p = &fun;”时是不正确的 是一个任务。
实际上,编译器试图解释“p = &fun;” 作为一个声明,所以“p”是一个声明符,“&fun”是一个初始化器,“p = &fun”形成一个初始化声明符(在 C 规范的形式语法中)。
将其解释为声明后,应在声明中的类型默认为 int(出于遗留原因),因此编译器本质上将其视为“int p = &fun;”,这是 p 的定义。因为 p 以前被定义为指向函数的指针,所以编译器会抱怨您正在用不同的类型重新定义 p。
对于语言语法学家:我无法弄清楚这怎么可能是形式语法中的声明。一个翻译单元将扩展为一个外部声明,一个外部声明将扩展为一个声明,一个声明将扩展为“declaration-specifiers init-declarator-list[opt];” (根据 C 标准中的 6.7)。声明说明符似乎至少需要存储类说明符、类型说明符、类型限定符或函数说明符中涉及的关键字之一。源代码中没有出现这样的关键字,因此这不能是声明。我怀疑编译器正在使用 1999 年标准之前的一些语法进行解析,所以这是遗留行为。尽管如此,错误消息清楚地表明编译器已经看到了两个定义,而不是一个定义后跟一个赋值。