簡體   English   中英

指向 POD 結構的 C/C++ 指針也指向第一個結構成員

[英]C/C++ Pointer to a POD struct also points to the 1st struct member

我可以假設 C/C++ 結構指針將始終指向第一個成員嗎?
示例 1:

typedef struct {
 unsigned char  array_a[2];
 unsigned char  array_b[5];
}test;
//..
test var;
//..

在上面的例子中 &var 總是指向 array_a 嗎? 同樣在上面的例子中是否可以將指針轉換為無符號字符指針並分別訪問每個字節?
示例 2:

function((unsigned char *)&var,sizeof(test));
//...
//...
void function(unsigned char *array, int len){
 int i;
 for( i=0; i<len; i++){
    array[i]++;
 }
}

那會正常工作嗎?

注意:我知道字符在結構中是字節對齊的,因此我假設上述結構的大小是 7 個字節。

對於 C 結構,是的,您可以依賴它。 這就是幾乎所有“面向對象”風格的 API 在 C 中的工作方式(例如 GObject 和 GTK)。

對於 C++,您只能將它用於“普通舊數據”(POD) 類型,這些類型保證在內存中的布局方式與 C 結構相同。 POD 類型的確切構成有點復雜,並且在 C++03 和 C++11 之間發生了變化,但關鍵是如果您的類型具有任何虛函數,那么它就不是 POD。

(在 C++11 中,您可以使用std::is_pod在編譯時測試結構是否為 POD 類型。)

編輯:這告訴你什么構成了 C++ 中的 POD 類型: http : //en.cppreference.com/w/cpp/concept/PODType

EDIT2:實際上,在 C++11 中,它不需要是一個 POD,只是“標准布局”,這是一個稍微弱一點的條件。 引用標准的第 9.2 節 [class.mem] 第 20 段:

指向標准布局結構對象的指針,使用 reinterpret_cast 適當轉換,指向其初始成員(或者如果該成員是位域,則指向它所在的單元),反之亦然。 [注意:因此,標准布局結構對象中可能存在未命名的填充,但不是在其開頭,這是實現適當對齊所必需的。 — 尾注 ]

來自 C99 標准第 6.7.2.1 節第 13 條:

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

因此,您的問題的答案是肯定的。

參考(見第 103 頁)

編譯器可以自由地添加填充並重新組織它認為合適的結構。 尤其是在 C++ 中,您可以添加(虛擬)函數,然后很可能在此之前隱藏虛擬表。 但當然,這是實現細節。 對於 C,這個假設是有效的。

對於 C,它主要是特定於實現的,但實際上規則(在沒有 #pragma pack 或類似的情況下)是:

  • 結構成員按它們聲明的順序存儲。 (這是 C99 標准所要求的,如前所述。)
  • 如有必要,在每個結構成員之前添加填充,以確保正確對齊。

所以給定一個結構

struct test{
char ch;
int i;
}

將在偏移量 0 處有 ch,然后是要對齊的填充字節,在偏移量 2 處有 i,然后在最后添加填充字節以使結構大小成為 8 字節的倍數。(在 64 位機器上,4 字節對齊在 32 位機器中可能允許)

所以至少在這種情況下,對於 C,我認為您可以假設 struct 指針將指向第一個數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM