タグ付けされた質問 「memory-layout」

3
Cでの構造体メモリレイアウト
私はC#のバックグラウンドを持っています。私はCのような低水準言語の初心者です。 C#では、 structのメモリはデフォルトでコンパイラによってレイアウトされます。コンパイラは、データフィールドを並べ替えたり、フィールド間に追加のビットを暗黙的に埋めたりすることができます。そのため、正確なレイアウトのためにこの動作をオーバーライドするために、いくつかの特別な属性を指定する必要がありました。 AFAIK、Cはstruct、デフォルトでは、のメモリレイアウトを並べ替えたり整列したりしません。ただし、見つけるのが非常に難しい小さな例外があると聞きました。 Cのメモリレイアウト動作とは何ですか?何を再注文/調整する必要がありますか?

7
Cでポインター比較はどのように機能しますか?同じ配列を指さないポインターを比較しても大丈夫ですか?
K&R(Cプログラミング言語第2版)の第5章で以下を読みました。 まず、特定の状況下でポインタを比較できます。もしpとq同じ配列のメンバーへのポイント、その後のような関係==、!=、<、>=、などの作業を適切に。 これは、同じ配列を指すポインターのみを比較できることを意味しているようです。 しかし、私がこのコードを試したとき char t = 't'; char *pt = &t; char x = 'x'; char *px = &x; printf("%d\n", pt > px); 1 画面に出力されます。 まず第一に、私はので、私は、未定義またはいくつかのタイプやエラーになるだろうと思ったptし、px(少なくとも私の理解では)同じ配列を指していません。 またpt > px、両方のポインタがスタックに格納されている変数を指しているため、スタックtが大きくなり、メモリアドレスがx?どちらがpt > px本当ですか? mallocが導入されると、さらに混乱します。また、8.7章のK&Rには、次のように書かれています。 ただし、によって返されるさまざまなブロックへのポインターをsbrk有意義に比較できるという前提はまだ1つあります。これは、配列内でのみポインタ比較を許可する標準では保証されていません。したがって、このバージョンのmallocは、一般的なポインタ比較が意味のあるマシン間でのみ移植可能です。 ヒープでmallocされたスペースを指すポインターとスタック変数を指すポインターを比較しても問題はありませんでした。 たとえば、次のコードは正常に機能し1、印刷されました。 char t = 't'; char *pt = &t; char *px = malloc(10); strcpy(px, pt); …

2
[[no_unique_address]]と同じタイプの2つのメンバー値
で遊ん[[no_unique_address]]でいc++20ます。 cppreferenceの例では、空のタイプEmptyとタイプがありますZ struct Empty {}; // empty class struct Z { char c; [[no_unique_address]] Empty e1, e2; }; どうやら、の大きさはZ、少なくともなければならない2ので、タイプのe1とe2同じです。 しかし、私は本当にZサイズが欲しいです1。これEmptyによりe1、さまざまなタイプのとを適用する追加のテンプレートパラメーターを使用して、いくつかのラッパークラスでラップすることについて考えましたe2。 template <typename T, int i> struct Wrapper : public T{}; struct Z1 { char c; [[no_unique_address]] Wrapper<Empty,1> e1; [[no_unique_address]] Wrapper<Empty,2> e2; }; 残念ながら、sizeof(Z1)==2。サイズをZ11 にするためのコツはありますか? 私はこれをテストしていますgcc version 9.2.1し、clang version 9.0.0 私のアプリケーションでは、フォームの空のタイプがたくさんあります …

1
空の基本クラスもメンバー変数であるときに、空の基本最適化が禁止されているのはなぜですか?
空のベース最適化は素晴らしいです。ただし、次の制限があります。 同じ基本型の2つの基本サブオブジェクトはオブジェクト表現内で異なるアドレスを持つ必要があるため、空の基本クラスの1つが最初の非静的データメンバーの型の型または基本でもある場合、空の基本最適化は禁止されています。最も派生したタイプの。 この制限を説明するには、次のコードを検討してください。static_assert失敗します。一方、どちらFooかBarを変更するか、代わりにから継承するBase2と、エラーが回避されます。 #include <cstddef> struct Base {}; struct Base2 {}; struct Foo : Base {}; struct Bar : Base { Foo foo; }; static_assert(offsetof(Bar,foo)==0,"Error!"); 私はこの振る舞いを完全に理解しています。私が理解していないのは、この特定の動作が存在する理由です。見落としではなく明示的な追加であるため、明らかに理由で追加されました。これの根拠は何ですか? 特に、2つの基本サブオブジェクトが異なるアドレスを持つ必要があるのはなぜですか?上記のBarはタイプでfooあり、そのタイプのメンバー変数です。Barの基本クラスがのタイプの基本クラスと関係がある理由foo、またはその逆の理由がわかりません。 実際、私はどちらかと言えば、それを含むインスタンス&fooのアドレスと同じであることを期待しBarます。他の状況で必要になるためです(1)。結局のところ、私はvirtual継承についてBase2特別なことは何もしていません。基本クラスは関係なく空であり、を使用したコンパイルは、この特定のケースでは何も壊れないことを示しています。 しかし、明らかにこの推論はどういうわけか間違っており、この制限が必要になる他の状況があります。 答えがC ++ 11以降であるとしましょう(私は現在C ++ 17を使用しています)。 (1)注:EBOはC ++ 11でアップグレードされ、特にに対して必須になりましたStandardLayoutType(ただしBar、上記でははではありませんStandardLayoutType)。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.