27

次の単純な構造体を検討してください。

struct A
{
    float data[16];
};

私の質問は:

floatが 32 ビットの IEEE754 浮動小数点数であるプラットフォームを想定すると(それが重要な場合)、 C++ 標準は の予想されるメモリ レイアウトを保証しstruct Aますか? そうでない場合、それは何を保証しますか、および/または保証を実施する方法は何ですか?

予想されるメモリ レイアウトとは、構造体が16*4=64メモリ内のバイトを占有し、連続する各バイトが配列4の 1 つのバイトで占有されることを意味します。つまり、予想されるメモリ レイアウトは、次のテスト パスを意味します。floatdata

static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));

(offsetofは標準レイアウトであるため、ここでは有効ですA。以下を参照してください)

これが気になる場合は、テストは実際にはgcc 9 HEAD の wandbox でパスします。このテストが失敗する可能性があるという証拠を提供するプラットフォームとコンパイラの組み合わせに出会ったことがありません。存在する場合は、それらについて学びたいと思います.

なぜ気にするのでしょうか:

  • alignasSSE のような最適化には、特定のメモリ レイアウト (および標準指定子を使用して処理できるため、この質問では無視するアライメント) が必要です。
  • このような構造体のシリアル化は、単に便利でポータブルなwrite_bytes(&x, sizeof(A)).
  • 一部の API (たとえば、OpenGL、具体的にはglUniformMatrix4fv など) は、この正確なメモリ レイアウトを想定しています。もちろん、ポインタをdata配列に渡してこのタイプの単一のオブジェクトを渡すこともできますが、これらのシーケンス (たとえば、マトリックス タイプの頂点属性をアップロードするため) には、特定のメモリ レイアウトが必要です。

実際に保証されるもの:

これらは、私の知る限り、次のことから期待できますstruct A

  • スタンダードなレイアウトです
  • 標準レイアウトであるため、ポインタは最初のデータ メンバ (おそらく ?) へのポインタにAなる可能性があります。つまり、最初のメンバのにパディングはありません。reinterpret_castdata[0]

(私の知る限り)標準によって提供されていない残りの2つの保証は次のとおりです。

  • プリミティブ型の配列の要素間にパディングはありません(これは間違っていると確信していますが、確認の参照を見つけることができませんでした)。
  • 内部の配列のにパディングはありません。datastruct A
4

2 に答える 2