簡體   English   中英

sizeof(T)== sizeof(int)?

[英]Is sizeof(T) == sizeof(int)?

我一直在研究草案標准,似乎無法找到我正在尋找的東西。

如果我有標准布局類型

struct T {
   unsigned handle;
};

然后我知道對於某些T t;reinterpret_cast<unsigned*>(&t) == &t.handle T t;

目標是創建一些vector<T> v並將&v[0]傳遞給C函數,該函數需要指向無符號整數數組的指針。

那么,標准是否定義sizeof(T) == sizeof(unsigned)並且這是否意味着T的數組將與unsigned數組具有相同的布局?

雖然這個問題涉及一個非常相似的主題,但我要問的是數據成員和類都是標准布局的特定情況,而數據成員是基本類型。

我讀過一些段落,似乎暗示, 也許這可能是真的,但沒有什么擊中了要害。 例如:

§9.2.17

兩個標准布局結構(第9節)類型是布局兼容的,如果它們具有相同數量的非靜態數據成員,並且相應的非靜態數據成員(按聲明順序)具有布局兼容類型

這不是我想要的,我不認為。

你基本上是在問:

struct T {
    U handle;
};

是否保證sizeof(T) == sizeof(U) 不它不是。

ISO C ++ 03標准的第9.2 / 17節說:

指向POD結構對象的指針,使用reinterpret_cast適當轉換,指向其初始成員(或者如果該成員是位字段,則指向它所在的單元),反之亦然。

假設你有一個struct T數組。 反之亦然部分意味着任何T::handle成員的地址也必須是struct T的有效地址。 現在,假設這些成員屬於char類型,並且您的聲明是正確的。 這意味着允許struct T具有未對齊的地址,這似乎不太可能。 該標准通常試圖不以這種方式綁定實現的手。 為了使您的聲明成立,標准必須要求允許struct T具有未對齊的地址。 並且必須允許所有結構,因為struct T可以是前向聲明的,不透明的類型。

此外,第9.2 / 17條繼續指出:

[注意:因此,在POD-struct對象中可能存在未命名的填充,但不是在其開頭,以實現適當的對齊。]

采用不同的方式,意味着不能保證永遠不會填充。

我已經習慣了Borland環境和他們:

T是你的情況下的結構,因此sizeof(T)是struct的大小

  • 這取決於#pragma pack和編譯器的對齊設置
  • 所以有時它可能比sizeof(unsigned)大!!!

出於同樣的原因,如果你有4Byte struct(uint32)和16Byte allign

  • struct T {uint32 u; };
  • 然后T a [100]與uint32 a [100]不同;
  • 因為T是uint32 + 12 Byte空格!

RETRACTION:論證是錯誤的。 引理2的證明依賴於隱藏的前提,即聚合類型的對齊嚴格地由其成員類型的對齊確定。 正如Dyp在評論中指出的那樣,該標准不支持該前提。 因此,接納為struct { Foo f }具有更嚴格的對准要求,即Foo


我會在這里扮演魔鬼的擁護者,因為似乎沒有其他人願意。 我將論證標准C ++( 我將在這里引用N3797 )保證sizeof(T) == sizeof(U)T是標准布局類(9/7)時,默認對齊具有單個默認對齊非靜態數據成員U ,例如,

struct T { // or class, or union
  U u;
};

它已經確定:

  • sizeof(T) >= sizeof(U)
  • offsetof(T, u) == 0 (9.2 / 19)
  • U必須是T的標准布局類型才能成為標准布局類
  • u有一個由完全sizeof(U)連續字節的內存組成的表示(1.8 / 5)

這些事實一起意味着T的表示的第一個sizeof(U)字節被u的表示占據。 如果sizeof(T) > sizeof(U) ,那么多余的字節必須是尾填充 :在T表示u之后插入的未使用的填充字節。

簡而言之,這個論點是:

  • 該標准詳細說明了實現可以向標准布局類添加填充的情況,
  • 這些情況中沒有一個適用於這個特定情況,因此
  • 符合要求的實現可能不會添加填充。

填充的潛在來源

在什么情況下標准允許實現將這種填充添加到標准布局類的表示中? 當需要對齊時:根據3.11 / 1,“ 對齊是一個實現定義的整數值,表示可以分配給定對象的連續地址之間的字節數。” 由於對齊原因,有兩個添加填充的提及:

  • 5.3.3 Sizeof [expr.sizeof] / 2狀態“當應用於引用或引用類型時,結果是引用類型的大小。當應用於類時,結果是對象中的字節數該類包括在數組中放置該類型對象所需的任何填充。大多數派生類的大小應大於零(1.8)。將sizeof應用於基類子對象的結果是基類類型的大小77當應用於陣列,其結果是在陣列中的總字節數。這意味着n個元素的數組的大小是一個元件的尺寸n倍“。

  • 9.2類成員[class.mem] / 13聲明“實現對齊要求可能導致兩個相鄰成員不能立即分配;因此可能需要空間來管理虛函數(10.3)和虛基類(10.1)。”

  • (值得注意的是C ++標准包含毛毯聲明允許實現到插入結構中的填充如在C標准,例如N1570(C11-ISH)§6.7.2.1/ 15“有可能是一個結構對象內無名填充,但不是在它的開頭。“和/ 17”在結構或聯合的末尾可能有未命名的填充。“)

很明顯,9.2的文本不適用於我們的問題,因為(a) T只有一個成員,因此沒有“相鄰成員”,(b) T是標准布局,因此沒有虛函數或虛基類(每個9/7)。 證明5.3.3 / 2不允許填充我們的問題更具挑戰性。


一些先決條件

引理1: 對於具有默認對齊的任何類型Walignof(W)除以sizeof(W)通過5.3.3 / 2,類型Wn個元素的數組的大小恰好是sizeof(W) n倍(即,數組元素之間沒有“外部”填充。 然后,連續數組元素的地址相隔sizeof(W)個字節。 通過對齊的定義,則必須使alignof(W)除以sizeof(W)

引理 2:對准alignof(W)默認的對准標准布局類的W只有默認對齊數據成員是最小公倍數LCM(W)的數據成員的比對(或1,如果是沒有的):給定可以分配W的對象的地址,還必須適當地對齊地址LCM(W)字節:成員子對象的地址之間的差異也將是LCM(W)字節,並且每個這樣的對齊。成員子對象划分LCM(W) 根據3.11 / 1中對齊的定義,我們將alignof(W)除以LCM(W) 字節的任何整數n < LCM(W)必須不被一些部件的對准整除vW ,使得僅是一個地址n從在其中的一個目的地址字節遠W可分配因此是不能適當地對齊W的對象,即, alignof(W) >= LCM(W) 鑒於alignof(W)除以LCM(W)alignof(W) >= LCM(W) ,我們alignof(W) == LCM(W)


結論

將該引理應用於原始問題具有即時結果: alignof(T) == alignof(U) 那么在數組中放置那種類型的對象需要多少填充? 沒有 由於第二個引理alignof(T) == alignof(U) ,並且alignof(U)sizeof(U)除以第一個,因此必須將alignof(T)除以sizeof(U)因此需要零字節的填充將T類型的對象放在數組中。

由於已經消除了所有可能的填充字節源,因此實現可能不會向T添加填充,並且我們根據需要具有sizeof(T) == sizeof(U)

暫無
暫無

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

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