あほい、ほい、
次のようなことをしても大丈夫かどうか疑問に思います。
class SomeClass
{
int bar;
};
SomeClass* foo = new SomeClass();
int offset = &(foo->bar) - foo;
SomeClass* another = new SomeClass();
*(another+offset) = 3; // try to set bar to 3
ただ好奇心が強い、ダンO
あほい、ほい、
次のようなことをしても大丈夫かどうか疑問に思います。
class SomeClass
{
int bar;
};
SomeClass* foo = new SomeClass();
int offset = &(foo->bar) - foo;
SomeClass* another = new SomeClass();
*(another+offset) = 3; // try to set bar to 3
ただ好奇心が強い、ダンO
技術的にはうまくいくかもしれないと思います。
ただし、いくつかの問題があります。バーはプライベートです。異なるタイプのポインターを混合しています(ポインター演算はポインタータイプに依存しています:intとcharのサイズが異なるため、int *+1とchar*+ 1の結果は異なります)。
メンバーへのポインタも検討しましたか?
#include <cassert>
struct SomeClass
{
int bar;
};
int main() {
int SomeClass::*mem_ptr = &SomeClass::bar;
SomeClass foo;
foo.*mem_ptr = 3;
assert(foo.bar == 3);
}
このアイデアはPODクラスには問題ありません(他の人があなたのサンプルコードのエラーについて言ったのと同じことです)。非PODクラスの場合、オブジェクトポインタからのオフセットだけでメンバーを識別する必要はありません。たとえば、メンバーが基本クラスの一部である場合、または同等に、派生クラスへのポインターにオフセットを適用したいが、複数または仮想継承が関係している場合を考えてみます。
しかし、あなたはメンバーへのポインタを知っていますか?
struct SomeClass
{
int bar;
};
// fieldtoset is a pointer-to-member
int SomeClass::*fieldtoset = &SomeClass::bar;
SomeClass* another = new SomeClass();
// syntax works as if "*fieldtoset" is "bar" (the member variable referand)
another->*fieldtoset = 3 // set bar to 3
何も問題はありませんが、注意しないと非常に危険です。
一方、あなたのコードは間違っています。(another + offset)のポインタタイプは何ですか?これは実際にはSomeClassへのポインターであり、intではないため、少なくともポインターを(int *)にキャストする必要があります。
*((int *)(another + offset)) = 3;
オフセットは常にポインタが指すタイプの単位であるため、注意が必要なもう1つの点です。つまり、intの長さが4バイトの場合、(int *)
ポインターに1を追加すると、実際には4が追加されるため、計算を行う前に、ポインターを(char *)にキャストすることをお勧めします。
だからあなたの例のために:
SomeClass* foo = new SomeClass();
int offset = (char *)&(foo->bar) - (char *)foo;
SomeClass* another = new SomeClass();
*((int *)((char *)another+offset)) = 3; // try to set bar to 3
あなたの例であなたがしていることは、ポインタの良い使い方ではありません。コンパイラが予想とは異なる動作をする場合は機能しない可能性があり、通常の方法を使用して、同じように簡単に、同じように効率的に、より少ないソースコードで実行できます。
有効な用途があれば、ポインタ演算に問題はありません。ただし、この言語でまだカバーされていないものはそれほど多くありません。
生のアドレスを見ると、それはうまくいくように見えますが、ステートメントの最初の人にとっては、int offset = &(foo->bar) - foo;
さまざまなポインター型を差し引こうとしています。したがって、それらをchar *にreniterpret_castすると、探しているものが得られるはずです。
これは複雑すぎてエラーが発生しやすいように見えますが、役に立ちません。
大丈夫です(通常、Windows DDKのCONTAINING_RECORDマクロのようにマクロを定義します)が、C++でこれが必要な理由は疑問です。通常、Cではこれらのタイプのトリックを使用します。