2

此代码导致编译错误“错误:使用不同类型重新定义'p'”:

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

但如果修改
void (*p)(); p = &fun;
void (*p)() = &fun,一切正常。


void (*p)(); p = &fun;和有什么区别
void (*p)() = &fun

4

4 回答 4

3

您不能在全局范围内执行任意分配;尝试:

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

void (*p)();

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

void (*p)() = &fun;有效,因为您正在创建和初始化一个变量。在全局范围内允许初始化。void (*p)(); p = &fun;创建一个未初始化的变量,然后为其赋值。赋值与初始化不同,需要在某个函数内部执行。

于 2012-07-15T14:36:46.983 回答
2
void (*p)();   // This is a declaration

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

是声明。

p = &fun;  // This is a statement

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

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

于 2012-07-15T14:42:20.243 回答
2

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

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

通常,您应该始终更喜欢初始化而不是赋值,这可以解决您的问题:

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

void (*p)() = &fun;  // declaration, definition and initialization of "p"
于 2012-07-15T14:42:56.310 回答
1

前面的三个答案没有回答问题,并且当它们表明“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 年标准之前的一些语法进行解析,所以这是遗留行为。尽管如此,错误消息清楚地表明编译器已经看到了两个定义,而不是一个定义后跟一个赋值。

于 2012-07-15T15:06:29.397 回答