2012-07-15 69 views
2

此代碼會導致編譯錯誤 「錯誤: 'P' 與不同類型的重定義」:爲什麼此代碼會導致編譯錯誤「重新定義」?

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

但是,如果修改
void (*p)(); p = &fun;
void (*p)() = &fun,一切都OK了。

什麼
void (*p)(); p = &fun;
void (*p)() = &fun之間的區別?

+1

[定義和分配指向全局和局部範圍函數的指針]可能的副本(http://stackoverflow.com/questions/5962358/definition-and-assignment-of-pointers-to-functions-at-global和本地範圍) – 2012-07-15 14:38:38

+0

您是否正在編譯所有警告和嚴格的ANSI模式(應該是這樣)? – 2012-07-15 14:39:31

回答

1

三個前回答不回答這個問題,是不正確的,當他們表明,「P = &fun;」是一項任務。

實際上,所述編譯器試圖解釋「P = &fun;」作爲聲明,所以「p」是一個說明符,「&樂趣」是一個初始化方法,和「p = &樂趣」形成一個init說明符(在C規範的形式語法中)。

將此解釋爲聲明後,應該在聲明中的類型默認爲int(因爲遺留原因),因此編譯器實質上將此視爲「int p = &fun;」,它是p的定義。因爲p先前被定義爲指向函數的指針,編譯器會抱怨你正在用不同的類型重新定義p。

對於語言語法學家:我無法弄清楚這可能是如何在形式語法中作出聲明。一個翻譯單元將擴展到一個外部聲明,一個外部聲明將擴展到一個聲明,並且一個聲明將擴展爲「聲明指定符init-declarator-list [opt];」(在C標準中每6.7) 。聲明說明符似乎至少需要一個涉及存儲類說明符,類型說明符,類型限定符或函數說明符的關鍵字。源中沒有這樣的關鍵字,所以這不能是一個聲明。我懷疑編譯器是用1999年標準之前的一些語法解析的,所以這是傳統行爲。儘管如此,錯誤信息卻使編譯器清楚地看到了兩個定義,而不是一個定義,後面跟着一個賦值。

3

您不能在全局範圍內執行任意賦值;請嘗試:

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

void (*p)(); 

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

void (*p)() = &fun;因爲您正在創建和初始化變量而工作。全球範圍內允許初始化。 void (*p)(); p = &fun;創建一個未初始化的變量,然後爲其分配值。分配的處理與初始化不同,需要在某個函數內執行。

2
void (*p)(); // This is a declaration 

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

的聲明。

p = &fun; // This is a statement 

是一個聲明。聲明不是聲明(聲明不是聲明)。

你不能在文件範圍有語句。 C只允許在塊範圍內有語句。

2

只有聲明和函數定義在全局範圍內有效;任務不是。

區別在於int n = 1;是一個帶初始化的聲明,而n = 1;是一個賦值。前者在全球範圍內是有效的,而後者則不是。函數指針也是如此。

作爲一項規則,你應該總是喜歡初始化任務,並能解決你的問題:

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

void (*p)() = &fun; // declaration, definition and initialization of "p" 
相關問題