C 为什么这段代码会导致编译错误;重新定义;?
此代码导致编译错误“错误:使用其他类型重新定义'p”: 但是如果修改C 为什么这段代码会导致编译错误;重新定义;?,c,function-pointers,C,Function Pointers,此代码导致编译错误“错误:使用其他类型重新定义'p”: 但是如果修改 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)(=&fun
,一切正常
void(*p)();p=&fun代码>和
void(*p)(=&fun
?您不能在全局范围内执行任意赋值;尝试:
void fun() {
printf("fun");
}
void (*p)();
int main(void) {
p = &fun;
return 0;
}
void(*p)(=&fun代码>之所以有效,是因为您正在创建和初始化一个变量。允许在全局范围内进行初始化<代码>无效(*p)();p=&fun代码>创建未初始化的变量,然后为其赋值。赋值与初始化不同,需要在某些函数中执行
void (*p)(); // This is a declaration
及
这些是声明
p = &fun; // This is a statement
这是一份声明。语句不是声明(声明也不是语句)
在文件范围内不能有语句。C只允许在块范围内有语句。只有声明和函数定义在全局范围内有效;作业不是
区别在于intn=1
是带有初始化的声明,而n=1代码>是一项作业。前者在全局范围内有效,而后者则无效。函数指针也是如此
通常情况下,您应该更喜欢初始化而不是赋值,这就解决了您的问题:
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"
前面的三个答案没有回答问题,并且当它们表明“p=&fun;”是一项作业时是不正确的
实际上,编译器试图将“p=&fun;”解释为一个声明,因此“p”是一个声明器,&fun是一个初始化器,“p=&fun”形成一个init声明器(在C规范的形式语法中)
将其解释为声明后,声明中应包含的类型默认为int(出于遗留原因),因此编译器本质上将其视为“int p=&fun;”,这是p的定义。因为p以前被定义为指向函数的指针,所以编译器会抱怨您正在用不同的类型重新定义p
对于语言语法学家:我不明白这怎么可能是正式语法中的声明。翻译单元将扩展为外部声明,外部声明将扩展为声明,声明将扩展为“声明说明符init declarator list[opt];”(根据C标准中的6.7)。声明说明符似乎至少需要存储类说明符、类型说明符、类型限定符或函数说明符中涉及的一个关键字。源中没有此类关键字,因此这不能是声明。我怀疑编译器正在使用1999年标准之前的一些语法进行解析,因此这是遗留行为。尽管如此,错误消息清楚地表明编译器看到了两个定义,而不是后面有赋值的定义。您是否在编译时使用了所有警告和严格的ANSI模式(您应该这样做)?
p = &fun; // This is a statement
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"