Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么这段代码会导致编译错误;重新定义;?_C_Function Pointers - Fatal编程技术网

C 为什么这段代码会导致编译错误;重新定义;?

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之所以有效,是因为您正在

此代码导致编译错误“错误:使用其他类型重新定义'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之所以有效,是因为您正在创建和初始化一个变量。允许在全局范围内进行初始化<代码>无效(*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"