質問
次のようなテスト構造の定義があります:
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-&gt; memberコンストラクトを持たずに、直接structメンバーを操作する他の方法はありますか?
解決
2つの質問をしているようです
&amp; testを3つの長さの整数配列として扱うことは安全ですか?
これを避けるのがおそらく最善です。これはC ++標準で定義されたアクションかもしれませんが、たとえそうであっても、あなたが働くすべての人がここで何をしているのか理解することはまずありません。構造体を埋める可能性があるため、標準を読んだ場合、これはサポートされていないと思いますが、わかりません。
名前なしでメンバーにアクセスするより良い方法はありますか
はい。 offsetof macro / operatorを使用してみてください。これにより、構造内の特定のメンバーのメモリオフセットが提供され、そのメンバーにポイントを正しく配置できます。
size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);
別の方法は、cのアドレスを直接取得することです
int* pointerToC = &(someTest->c);
他のヒント
いいえ、わかりません。コンパイラーは、構造体メンバー間にパディングを自由に導入できます。
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
}
おそらく offsetof
マクロを探しています。これにより、メンバーのバイトオフセットが取得されます。その後、そのオフセットでメンバーを操作できます。ただし、このマクロは実装固有です。 stddef.h
をインクルードして、動作させます。
これはおそらく安全ではなく、100%読み取り不能です。そのため、実際の製品コードではこの種のコードは受け入れられません。
setメソッドとboost :: bindを使用して、この変数を変更するファンクターを作成します。
パディング/アラインメントの問題は別の答えが持ち出しているだけでなく、コードは厳密なエイリアシング規則に違反しています。つまり、最適化されたビルドでは破損する可能性がありますこのタイプの動作を中断します)。基本的に、 test * t
と int * ptr
は異なる型であるため、コンパイラはメモリの異なる部分を指していると想定し、操作を並べ替える場合があります。
この小さな変更を検討してください:
test* t = new test;
int* ptr = (int*) t;
t->c = 13;
ptr[2] = 15;
cout << t->c;
最後の出力は、コンパイラが使用する操作の順序に応じて、 13
または 15
のいずれかになります。
標準のパラグラフ9.2.17によると、構造体が POD :
POD-structオブジェクトへのポインター、 を使用して適切に変換 reinterpret_cast、そのポイント 最初のメンバー(またはそのメンバーが ビットフィールド、次にユニットに それが存在します)およびその逆。 [注意: したがって、無名の可能性があります POD-structオブジェクト内のパディング、 ただし、必要に応じて、最初からではありません 適切なアライメントを達成します。 ]
ただし、標準では、アクセス指定子(< code> private:、 protected:
、または public:
)。したがって、 struct test
の最初の部分を3つの整数の配列として扱うことは、技術的には未定義の動作です。