0.c
#include <stdio.h>
struct test{
int a;
};
struct test get(int in);
int main(){
struct test t = get(1234);
printf("%d\n",t.a);
return 0;
}
1.c
struct test{
char a; // Note this is char instead of int.
};
struct test get(int in){
struct test t = {in};
return t;
}
struct test有兩種不同的定義。一個 withint和另一個 withchar作為它的資料型別。
這是未定義的行為嗎?C 沒有正式的one dentition rule像 C 這樣的帖子,這篇文章說多個定義可以嗎?是否允許不同的翻譯單元定義同名的結構?
uj5u.com熱心網友回復:
這是未定義的行為嗎?
是的。
這篇文章說多個定義可以嗎?
當然,但當它們在兩個 TU 之間使用時就不行了。
問題甚至不在于struct test t = get(1234);,而在于之前,只是在函式宣告上struct test get(int in);。這是規則6.2.7:
2 參考同一物件或函式的所有宣告應具有兼容的型別;否則,行為未定義。
從6.7.6.3p15 開始:
要使兩種函式型別兼容,兩者都應指定兼容的回傳型別 [...]
從6.2.7p1 開始:
[...] 在單獨翻譯單元中宣告的兩個結構 [...] 如果它們的標簽和成員滿足以下要求,則它們是兼容的:[...] 如果兩者都在其各自翻譯單元內的任何地方完成,則以下附加要求apply:它們的成員之間應該是一一對應的,這樣每對對應的成員都宣告為兼容的型別。
File0.c宣告函式getatstruct test get(int in);和 file1.c宣告函式getat struct test get(int in){...}(定義也是宣告)。兩者具有相同的名稱,因此它們指代相同的功能。
兩者都有回傳型別struct test。In0.c struct test有一個 type 成員int,in1.c struct test有一個 type 成員char。兩個檔案中兩個結構體的第一對成員的型別不兼容,因此型別struct test不兼容,因此函式宣告不兼容,因此代碼的行為未定義。
uj5u.com熱心網友回復:
這是未定義的行為嗎?
是的。
C 并沒有像 C 那樣官方有一個牙列規則,這篇文章說多個定義可以嗎?是否允許不同的翻譯單元定義同名的結構?
C 沒有與 C 完全相同的單一定義規則,但它確實有類似的規則。每個識別符號最多可以有一個外部定義,在程式中的任何位置都有外部鏈接。在任何給定的翻譯單元中,最多可以有一個具有內部鏈接的識別符號的定義。在該識別符號的范圍內,在同一命名空間中最多可以有一個沒有鏈接的識別符號定義,除了 typedef 可以相同地重新定義。
您參考的答案解釋說,由于結構型別宣告沒有鏈接,您可以在不同的翻譯單元中重復使用結構標簽,但這不足以滿足本問題中呈現的代碼的需求。
在這里,為了明確定義程式的行為,其中get()任何位置的所有函式宣告都必須相互兼容(C17,6.2.7/2)。宣告包括定義,這意味著get()在其原型中指定的型別0.c必須與其在 中的定義兼容1.c。“兼容”是 C 中定義的術語,包含在語言規范的第 6.2.7 節中,包括其他幾個參考。
函式宣告的規則在第 6.7.6.3/15 段。最相關的規定是第一句話:
對于要兼容的兩個函式型別,都應指定兼容的回傳型別。
我們回到 6.2.7/1 對結構型別兼容性的定義:
如果它們的標簽和成員滿足以下要求,則在單獨的翻譯單元中宣告的兩個結構、聯合或列舉型別是兼容的: 如果一個用標簽宣告,另一個應用相同的標簽宣告。如果兩者都在其各自翻譯單元內的任何地方完成,則適用以下附加要求:其成員之間應存在一一對應關系,以便每一對對應成員都宣告為兼容型別;[...] 如果對中的一個成員使用名稱宣告,則另一個成員使用相同的名稱宣告。對于兩個結構體,相應的成員應以相同的順序宣告。
您的兩種struct test型別(perforce)使用相同的標簽定義,并且它們的成員具有相同名稱的相同順序,但是它們對應的成員沒有兼容的型別(細節留作練習)。結果,函式get()in的宣告與in0.c的定義不兼容1.c,因此程式具有未定義的行為——即使get()從未被呼叫,仍然會如此。
uj5u.com熱心網友回復:
C 中這樣的代碼的問題在于,編譯器只存盤函式的外部名稱,而沒有提供有關它們的引數和回傳型別的資訊。因此,兩個翻譯單元都看不到彼此中的函式宣告。它們只提供函式的外部名稱get。并且聯結器認為函式的定義對應于兩個名稱get。但是宣告和定義中參考的結構型別不同且不兼容。所以程式有未定義的行為。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/324799.html
標籤:C
