2017-01-25 20 views
7
struct parent 
{ 
    char a; 
    char b; 
}; 

struct child 
{ 
    struct parent parent; 
    int c; 
    char d; 
}; 

struct grandchild 
{ 
    struct child child; 
    long e; 
}; 

void print_parent_val(struct parent *p) 
{ 
    printf("%d\n", p->a); 
} 

int main (int argc, char **argv) 
{ 
    struct grandchild g; 
    g.child.parent.a = 69; 
    print_parent_val((struct parent *)&g); 
    return 0; 
} 

該程序編譯(無警告)並運行正常,並按預期打印69。我從來沒有見過任何實現這種繼承技術的代碼,所以我很猶豫要把它看成「OK」。這個C繼承實現是否包含未定義的行爲?

編輯:如何將孫子轉換爲小孩?中期轉換也有可能嗎?

void print_parent_val(struct child *c) 
{ 
    printf("%c\n", c->d); 
} 

int main (int argc, char **argv) 
{ 
    struct grandchild g; 
    g.child.parent.a = 69; 
    g.child.d = 'w'; 
    print_parent_val((struct child *)&g); 
    return 0; 
} 
+0

這是衆所周知的類型雙關嗎?像在Win32中一樣,'NMHDR'和第一個memeber是指向'NMHDR'的結構?我不確定 – stackptr

+0

您可能還想看看與您的問題有關的'man 3 offsetof'。 –

+0

你可能從來沒有見過實現這種技術的代碼,但是我已經寫了*這樣的代碼。基於Sourav在他的回答中提出的基本相同的論點,在使自己確信其行爲是明確的之後。我相信,我離第一個寫這樣的代碼還很遠。 –

回答

7

我所看到的,沒有任何的未定義行爲這裏範圍。

引用C11,章§6.7.2.1,結構和聯合說明符,(重點煤礦

內的結構對象,非位字段構件和單元,其中位字段 駐留的地址按其聲明的順序增加。 指向經過適當轉換的 結構對象的指針指向其初始成員(或者如果該成員是 位字段,則指向其所在的單位),反之亦然。 在結構對象中可能存在未命名的 填充,但不在其開始處。

因此,以目前的片段(和方法),你應該很好去。

+0

我已經對你的問題進行了一些編輯,但是我相信這個引用也可以回答它。 –

+0

你是正確的,結構的內存佈局將允許這個工作,_if_嚴格的別名是不是一件事情。用'-fno-strict-aliasing',這是正確的答案! –

+0

@HaldeanBrown這裏明確提到了在開始時沒有填充,那麼這是如何違反嚴格的別名規則? –