14

この質問の反例を考えているうちに、私は思いつきました:

struct A
{
    alignas(2) char byte;
};

しかし、それが合法で標準的なレイアウトである場合、これとレイアウト互換struct Bですか?

struct B
{
    char byte;
};

さらに、

struct A
{
    alignas(2) char x;
    alignas(4) char y;
};
// possible alignment, - is padding
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
//  x  -  -  -  y  -  -  -  x  -  -  -  y  -  -  -

struct B
{
    char x;
    char y;
}; // no padding required

union U
{
    A a;
    B b;
} u;

と の共通の初期シーケンスはAありBますか? もしそうなら、それはA::y&を含みB::yますか? つまり、UB を呼び出さずに次のように記述してもよろしいでしょうか?

u.a.y = 42;
std::cout << u.b.y;

(C++1y / "fixed C++11" の回答も歓迎)


  • 配置については [basic.align] を、配置指定子については [dcl.align] を参照してください。

  • [basic.types]/11 は、基本型について「2 つの型T1T2が同じ型である場合、T1T2はレイアウト互換型です」と述べています。(根本的な問題はA::byte、 とB::byteがレイアウト互換の型を持っているかどうかです)

  • [class.mem]/16 「2 つの標準レイアウト構造体型は、同じ数の非静的データ メンバーを持ち、対応する非静的データ メンバー (宣言順) がレイアウト互換型を持っている場合、レイアウト互換性があります。」

  • [class.mem]/18 "2 つの標準レイアウト構造体は、対応するメンバーがレイアウト互換の型を持ち、どちらのメンバーもビットフィールドではないか、どちらも 1 つのシーケンスに対して同じ幅のビットフィールドである場合、共通の初期シーケンスを共有します以上の初期メンバー。」

  • [class.mem]/18 「標準レイアウト共用体に共通の初期シーケンスを共有する 2 つ以上の標準レイアウト構造体が含まれている場合、および標準レイアウト共用体オブジェクトに現在これらの標準レイアウト構造体の 1 つが含まれている場合、それは許可されます。それらの共通の最初の部分を検査します。」

もちろん、言語弁護士レベルでは、別の質問は、共通の初期シーケンスの検査が「許可されている」とはどういう意味かということです。u.b.x他の段落が上記の未定義の動作(初期化されていないオブジェクトからの読み取り)を行う可能性があると思います。

4

3 に答える 3

2

私は C++11 標準について話すことはできませんが、私はファームウェア/マイクロチップ プログラマーであり、長い間存在する機能 (プラグマ パック、アライメント属性) を使用しなければなりませんでした。

使用alignasは「標準レイアウト」とは見なされないため、すべての意味は無用です。標準レイアウトは、1 つの固定配置分布を意味します (アーキテクチャごとに - 通常はすべてが であるalign(min(sizeof,4))か、一部が である可能性がありますalign(8))。標準はおそらく明白なことを言いたがっています: 特別な機能 ( align, pack) を使用しなくても、構造が同じように見える場合 (同じ型が同じ順序である場合)、同じアーキテクチャ上で互換性があります。それ以外の場合、互換性がある場合とない場合があります-アーキテクチャによって異なります(あるアーキテクチャでは互換性がありますが、別のアーキテクチャでは異なる場合があります)。

この構造体を考えてみましょう:

struct foo{ char b; short h; double d; int i; };

1 つのアーキテクチャ (x86 32 ビットなど) ではこのように見えますが、Itanium または ARM では実際には次のようになります。

struct foo{char b, **_hidden_b**; short h; **int _maybe_hidden_h**; double d; int i;}  

注意_maybe_hidden_h- 古い AEABI (最大 4 に整列) または 64 ビット/8B 整列では省略できます。

x86 標準レイアウト (pack(1)):

alignas(1) char b; alignas(1) short h; alignas(1) double d; alignas(1) int i;  

32 ビット アライメント標準レイアウト (pack(4) - ARM アーキテクチャ、古いバージョン - EABI)

alignas(1) char b; alignas(2) short h; **alignas(4) double d**; alignas(4) int i;  

64 ビット アライメント標準レイアウト (pack(8) - Itanium 以降の ARM/AEABI)

alignas(1) char b; alignas(2) short h; **alignas(8) double d**; alignas(4) int i;

あなたの例に:
offsetof(A,y) = 4whileoffsetof(B,y) = 2とユニオンはそれを変更しません(したがって&u.a.y != u.b.y

于 2014-07-26T11:03:12.323 に答える
0

(根本的な問題は、 A::byte と B::byte がレイアウト互換の型を持っているかどうかです)

はい。これは不可欠な部分です。alignas-attributeは、タイプではなく、宣言されたエンティティに属します。std::is_sameとで簡単にテストできますdecltype

つまり、UB を呼び出さずに次のように記述してもよろしいでしょうか?

したがって、これは UB ではありません。関連する段落はあなたによって引用されています。

編集: メンバー間のパディングが (または実装で) 定義されていない (§9.2/13) ため、これはもちろん UB になる可能性があります。y ではなく x にアクセスすると思っていたので、誤って例を読み違えてしまいました.

于 2014-05-02T15:44:54.733 に答える