2017-03-17 10 views
1

Cでは、構造体の最初の要素は構造体自体と同じアドレスを持ちます。最初の要素がPODの場合、C++の非POD構造体でも同じことが言えますか?C++非ポッド開始アドレス

struct bar 
{ 
    struct bar *p1, *p2; 
    unsigned char h; 
} 

struct foo 
{ 
    struct bar node; 
    int a; 

    private: 
     int x; 
}; 

int main(void) 
{ 
struct foo A; 
struct bar *ptr; 

ptr = &A.node; 

struct foo *n = ((struct foo*)((char*)(ptr)-(unsigned long)(&((struct foo*)0)->node))); 

return 0; 
} 

私は「多分offsetofはマクロが誤って使用された... NULLオブジェクトの非静的データメンバ 『FOO ::ノード』への不正なアクセス」を取得:このコードは与えられた例

、警告。

私の質問はこれです - これはnon-POD構造体ですが、 'node'はfoo(同じアドレス)の先頭にあると思いますか?

はい、私はちょうど再解釈キャストを使用することができますし、私は警告を取得しない場合:だから

struct foo *o = reinterpret_cast<struct foo*>(ptr); 

をC++の構造体は、公共PODデータで始まる場合、最初の要素はオブジェクトのアドレスを共有します標準ごとに?

おかげ

--edit-- In a class with no virtual methods or superclass, is it safe to assume (address of first member variable) == this?は、可能な答えと指摘しました。 「アクセス・オプションを介在させずに宣言された(非ユニオン)クラスの非静的データ・メンバーは、後のメンバーがクラス・オブジェクト内でより高いアドレスを持つように割り当てられます」ということに言及しています。私の場合は、オブジェクト自体と同じアドレスです。

標準はそれについて何も言わないので、私はそれが当てはまるとは思いません。私は、ポインタの構造体の終わりにオブジェクトを変更し、必要に応じてそれらを割り当てることに対処する必要があります。

+0

C++では、 'struct'はstruct型の変数を宣言するためには必要ありません。 –

+2

[cppreference](http://en.cppreference.com/w/cpp/language/data_members)から:* "アクセス制御の異なるメンバーは不特定の順序で割り当てられます(コンパイラはそれらをグループ化することがあります)" * - 'bar'が最初のメンバとして確保されていることを保証できないことを意味するはずです。 – UnholySheep

+1

' struct'は仮想テーブルポインタを持ち、最初にあるプラットフォームで私が知っているものと一致します。そうではありません。 – Slava

答えて

-4

仮想テーブルは構造体の一部である可能性があるので、短い答えはnoです。現在、vtableは標準の一部ではありません。それらは仮想的なものを実装して多形性を実現する単なるメカニズムです。すべての実用的な理由から答えはまだノーです。

次のコードを参照してください。

#include <iostream> 

using namespace std; 

struct bar 
{ 
    struct bar *p1, *p2; 
    unsigned char h; 
}; 

struct foo 
{ 
    struct bar node; 
    int a; 

    private: 
     int x; 
}; 

int main(void) 
{ 
    struct foo A; 
    struct bar *ptr; 

    A.node.p1 = new bar(); 
    A.node.p2 = new bar(); 
    ptr = &A.node; 

    struct foo *n = ((struct foo*)((char*)(ptr)-(unsigned long)(&((struct foo*)0)->node))); 
    cout << n->a << endl; 

    return 0; 
} 

コードがg++ -Wall -Werror -pedantic -std=c++14 test.cppでコンパイルされています。問題は、あなたがp1p2のメモリを割り当てなかったと思います。

+0

これは何を示すはずですか?それはどのように質問に答えるのですか(具体的には標準について質問しています)? – UnholySheep

+0

@UnholySheepよく、pedantic flagは、このコードが標準に準拠しており、問題がないことを保証します。ちょうどOPはそれを正しく書いていません – user902384

+0

コメントありがとうございますが、p1とp2の割り当ては無関係です(ポインタとして存在します)。 – Marc

1

標準は、標準的なレイアウトクラスオブジェクトは、任意の非静的データメンバを持つ場合、そのアドレスは、その最初の非静的のアドレスと同じである[class.mem]/19

に言いますデータメンバー。それ以外の場合は、そのアドレスは、その最初の基本クラスのサブオブジェクトのアドレスと同じです(存在する場合)。 [注:したがって、標準レイアウトの構造体 オブジェクト内に名前のないパディングがあるかもしれませんが、適切な位置合わせを達成するために必要であれば、その先頭にはないことがあります。クラスがある場合-endノート]

だからあなたは標準ではありません標準レイアウトクラスは、第1部材のアドレスは、クラスのアドレスで保証しています。あなたのケースでは、それはそれが最初の基本クラスのアドレスであることを示します。最初のメンバーがオブジェクトのアドレスを共有していることを意味する基本オブジェクトを持っていないので、オブジェクトの先頭にパディングすることはできません。これは、fooのアドレスがそのアドレスであることを意味し、barメンバーであり、barは標準レイアウトクラスであるため、p1のアドレスにもなります。

ただし、最初のメンバーの後に任意のメンバーを取得しようとすると、未定義の動作になります。クラスの型(これにはstructを含む)は、整列のためにクラスのいずれかのメンバの間にパディングを持つことができます。つまり、他のメンバーと最初のメンバーとの関係が正確にわからないことを意味します。

+0

"bar"が次のようなものだった場合: struct foo { struct bar node; int a; objectx X; オブジェクトY; }; "node"のreinterpret_castから "foo"のアドレスを取得できましたが、それ以降は何もありません。 – Marc

+0

私がよく分からないこと: 'reinterpret_cast'オブジェクトのポインタ/アドレスを最初の非静的メンバーにすると、厳密なエイリアシングルールが破られるはずです。あるいは、このカテゴリは* "AliasedTypeとDynamicTypeの両方に分類されます(それぞれのレベルで複数レベル、おそらくはcv修飾されている可能性があります)、同じ型のポインタ" T "*([reinterpret_cast'](http:// en.cppreference.com/w/cpp/language/reinterpret_cast)リファレンスページ) – UnholySheep

+0

@Marcはい。もし 'foo'が' struct foo {struct bar node; int a;オブジェクトx;客観的なY; }; 'それは標準のレイアウトタイプであり、'&foo_object'と '&foo.object.node'は同じアドレスになります。 'a'のアドレスは、' node'と 'a'の間にパディングがある可能性があるので、あなたは知っています。 – NathanOliver

関連する問題