2

次のようなテスト構造体定義があります。

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

そして、どこかで私はそれをこのように使用しています:

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

これは私の Windows では正しく動作します。期待どおりに 15 が出力されますが、安全ですか? 変数がメモリ内のその場にあることを本当に確信できますか-特にそのような結合された構造体の場合(たとえば、f はコンパイラの 5 番目の単語ですが、6 番目の変数です)?

そうでない場合、実際にコードに struct->member 構造を持たずに構造体メンバーを直接操作する方法はありますか?

4

8 に答える 8

13

2つの質問をしているようです

&test を長さ 3 の int 配列として扱っても安全ですか?

これは避けたほうがいいのではないでしょうか。これは C++ 標準で定義されているアクションかもしれませんが、たとえそうであったとしても、一緒に作業するすべての人がここで何をしているのかを理解することはまずありません。構造体をパディングする可能性があるため、標準を読んだ場合、これはサポートされていないと思いますが、よくわかりません。

名前なしでメンバーにアクセスするより良い方法はありますか?

はい。offsetofマクロ/演算子を使用してみてください。これにより、構造内の特定のメンバーのメモリ オフセットが提供され、そのメンバーにポイントを正しく配置できるようになります。

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

別の方法は、 c のアドレスを直接取得することです

int* pointerToC = &(someTest->c);
于 2009-03-08T15:08:52.733 に答える
5

いいえ、確信が持てません。コンパイラは、構造体メンバー間にパディングを自由に導入できます。

于 2009-03-08T15:04:11.437 に答える
4

JaredPar の回答に追加するには、C++ のみ (プレーン C ではない) の別のオプションは、メンバーへのポインター オブジェクトを作成することです。

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}
于 2009-03-08T15:52:07.077 に答える
2

offsetofあなたはおそらくマクロを探しています。これにより、メンバーのバイトオフセットが取得されます。その後、そのオフセットでメンバーを操作できます。ただし、このマクロは実装固有であることに注意してください。それを機能させるために含めますstddef.h

于 2009-03-08T15:12:03.663 に答える
1

おそらく安全ではなく、100% 読み取り不能です。したがって、そのようなコードは実際の製品コードでは受け入れられません。

于 2009-03-08T15:09:19.537 に答える
0

標準のパラグラフ 9.2.17 によると、構造体がPODである場合、構造体へのポインターをその最初のメンバーへのポインターにキャストすることは実際には合法です。

reinterpret_cast を使用して適切に変換された POD 構造体オブジェクトへのポインターは、その最初のメンバー (または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。[注: したがって、POD 構造体オブジェクト内に名前のないパディングがある場合がありますが、適切な配置を実現するために必要に応じて、先頭にはありません。]

private:ただし、標準では、構造体 (POD 構造体であってprotected:public:)のレイアウトについて保証していません。彼ら。したがって、 your の最初の部分をstruct test3 つの整数の配列として扱うことは、技術的に未定義の動作です。

于 2009-03-10T17:03:28.463 に答える
0

set メソッドと boost::bind を使用して、この変数を変更するファンクターを作成します。

于 2009-03-08T15:34:08.213 に答える
0

他の回答が提起したパディング/アライメントの問題は別として、コードは厳密なエイリアシング規則に違反しています。つまり、最適化されたビルドで壊れる可能性があります (MSVC がこれをどのように行うかはわかりませんが、GCC-O3はこの種の動作で壊れます)。基本的に、test *tint *ptrは型が異なるため、コンパイラはこれらがメモリの異なる部分を指していると想定し、操作の順序を変更することがあります。

このマイナーな変更を検討してください。

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

最後の出力は、コンパイラが使用する操作の順序に応じて、13または のいずれかになります。15

于 2009-03-08T16:18:00.523 に答える