2011-10-25 54 views
5

這是this question的後續行動。在casts/assignment中不兼容的結構類型?

我試圖避免使用顯式的typedef到一個數組複製到另一個通過強制轉換是這樣的:

#include <stdio.h> 

int main(void) 
{ 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    *(struct{int _[3];}*)dst = *(struct{int _[3];}*)src; 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 
    return 0; 
} 

用gcc我得到arrcpy.c:8: error: incompatible types in assignment,但與開放式WATCOM它編譯罰款(並按我期望的那樣工作,打印1到3)。

gcc的行爲是否符合標準?如果是,相關的章節是什麼?我不明白爲什麼兩個相同的類型定義struct{int _[3];}在gcc的眼中不相同(或兼容)。

編輯:我完全知道這是一種糟糕的編碼風格。問題是關於另一件事。我很好奇,如果gcc的行爲背後有一個合理的理由,那麼它是合法的。

+0

無論這是可能是一個問題。但編寫代碼絕對是一種可怕的方式,除非你準備提交混淆的C比賽的提交。 – TJD

+0

你爲什麼要避免typedef?這將有助於分解冗餘結構規範。 –

+3

'memcpy(3)'有什麼問題? – sarnold

回答

6

gcc的行爲是正確的,類型是兩個無關的未命名的結構。每個結構具有相同的內存佈局,但名稱不同。如果你真的想這樣做,那麼使用typedef。

+1

即使使用'typedef',type-punning也會導致**未定義的行爲**。無論如何,爲了解決OP的問題,正確回答爲什麼代碼是無效的,而不是OP似乎已經理解「應該」使用的替代方案的建議。 –

1

爲什麼不使用memcpy

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    memcpy(dst, src, 3 * sizeof(int)); 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 
    return 0; 
} 

或大小,而不是3:sizeof(dst)/sizeof(dst[0])

編輯:有了您的編輯,我只能假設,與outis' answer,編譯器看到這兩個結構的定義只是,兩個不同結構類型。即使它們可能包含相同的數據,它們也是兩種不同的類型。

+0

我知道如何使用memcpy()。查看問題更新。 –

+0

噢好吧,在我看到編輯之前張貼。 – AusCBloke

1

基本上,類型等價不是在C中的structural等價。C使用nominative type system

根據第C99的6.7.2.1-7:

一個struct聲明列表的一個結構,或工會說明符的出現宣告一個新的類型,一個翻譯單元內。 struct-declaration-list是結構或聯合成員的一系列聲明。如果struct-declaration-list不包含任何命名成員,則行爲是未定義的。直到}終止列表之後,該類型纔是不完整的。

struct-declaration-liststruct-or-union-specifier來從C語法(第6.7.2.1):

 
struct-or-union-specifier: 
    struct-or-union identifieropt { struct-declaration-list } 

struct-or-union: 
    struct 
    union 

即使兩個不同的結構具有相同的存儲器佈局,它們是不同的類型。

如果要避免污染全局名稱空間,可以在本地將結構聲明爲您使用它的函數。

#include <stdio.h> 

int main(void) { 
    // struct T is only visible in main() 
    struct T {int _[3];}; 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    *(struct T*)dst = *(struct T*)src; 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 

    return 0; 
} 

void fails(void) { 
    // will cause a compilation error, because struct T is an incomplete type. 
    struct T t; 
} 
+2

問題是關於C,而不是C++及其類和重載函數。 –

+0

這個問題足夠模糊,C和C++是不同語言的事實絕對重要。 –

1

兩個struct定義是不兼容的:

從C99 6.2。7:

如果類型相同,兩種類型具有兼容類型。用於確定兩種類型是否兼容附加 規則描述 在6.7.2類型說明符,在6.7.3類型限定符,並且在 6.7.5用於說明符。此外,二元結構,聯合或枚舉在不同的翻譯單位聲明類型兼容 如果他們的標籤和成員滿足以下要求...

的類型是不一樣的。如果他們是在不同的翻譯單位申報的,那麼他們將是兼容的。

然而,即使他們是兼容的,你的代碼仍然會發生未定義行爲,至少有兩個原因:

  1. 它使用保留名稱「_」。
  2. 訪問對象作爲不同類型的(除非通過字符指針,工會等結構)是不允許的。
+0

你指的是7.1.3?:'以下劃線開頭的所有標識符,始終保留用作與兩個普通和標籤名稱的文件範圍標識符 spaces.' –

+0

@Alex:是的,就是這樣。 – wnoise