2011-07-27 6 views
1

私のバグは数時間後に見つけられ、次のプログラムで隔離されました。問題は、構造体へのポインタを使用するときにpst2変数の値が計算される方法にあります。 charへのポインターを使用すると、すべて正常に動作します。どうしてこれなの?
(GCC/G ++バージョンの使用:(Debianの4.4.5-8)4.4.5)(不思議に思っている人のために。私は、通常のオフセットでデータ・グループを含むファイル・バッファにアクセスしています)
C++のポインタの算術奇妙さ

#include <iostream> 
#include "testpa.h" 

#pragma pack(push) 
#pragma pack(1) 
//--------------------------- 
struct st_one 
{ 
    int i; 
    char c; 
}; 
//--------------------------- 
struct st_two 
{ 
    long l; 
    int i; 
}; 
#pragma pack(pop) 

//=========================== 
int main() 
{ 
    int n=1024, np1=sizeof(st_one); //, np2=sizeof(st_two); 
    st_one *pst1, *pst1a; 
    st_two *pst2, *pst2a; 
    char *pc1, *pc2, *pc1a, *pc2a, *pb; 

    pb = new char[n]; 

    pst1 = (st_one*)(pb); 
    pst2 = (st_two*)(pst1 + np1); //using pst1 
    pc1 = (char*)(pb); 
    pc2 = (char*)(pc1 + np1); //using pc1 

    pst1a = (st_one*)(pb); 
    pst2a = (st_two*)(pb + np1); //using pb 
    pc1a = (char*)(pb); 
    pc2a = (char*)(pb + np1); //using pb 

    std::cout << "\npb = " << (long)pb; 
    std::cout << "\n-----"; 
    std::cout << "\npst1 = " << (long)pst1 << "\tpst2 = " << (long)pst2; 
    std::cout << "\npc1 = " << (long)pc1 << "\tpc2 = " << (long)pc2; 
    std::cout << "\n-----"; 
    std::cout << "\npst1a = " << (long)pst1a << "\tpst2a = " << (long)pst2a; 
    std::cout << "\npc1a = " << (long)pc1a << "\tpc2a = " << (long)pc2a; 
    std::cout << "\n-----\n"; 

    return 0; 
} 

出力:

pb = 19546128 

pst1 = 19546128   pst2 = 19546153 <--- WRONG! 
pc1 = 19546128   pc2 = 19546133 

pst1a = 19546128  pst2a = 19546133 
pc1a = 19546128  pc2a = 19546133 
+0

どのように間違っているかはわかりません。あなたはどんな行動を期待していますか? –

+0

これは難しいことです。 'pst1 [offset] .c'で何が問題になっていますか?コンパイラが作業をするようにしてください。とにかくポインタの算術演算を行う予定であり、エラーが発生する可能性は低いです。 – msw

答えて

8

私には正常に見えます。ライン:

(pst1 + np1) 

あなたがきた値に対応pst1 S値は25であるnp1 * sizeof (st_one)バイト(のsizeof = 5)だけインクリメントされることを意味し、どのようにpst1点にst_onenp1インスタンスを追加します出力される。それはcharポインタであるため、

(pst1 + 1) 

pc1値が働くので、ラインは:代わりに上記の、私はあなたが望んでいたと思います

(pc1 + np1) 

は5バイトである、pc1np1 * sizeof (char)バイトが追加されます。

ポインタをインクリメントすると、ポインタは次のバイトではなくメモリの次の要素を指し示します。

+0

私は常に、ブラケット内の値が最初に計算され、外部操作が行われるという印象を受けました。この場合、pst1とnp1の整数値がポインタとしてキャストされる前に追加されると考えられます。 – slashmais

+0

ああ!私はミスをした場所を強調しました - ありがとう。 – slashmais

3

これは自動的に行われるため、sizeof(x)を追加しないでください。 ++ pのようにポインタをインクリメントすると、アドレスはオブジェクトのサイズだけインクリメントされ、次のポインタを指すようになります。

ポインタに1を追加することは、++ pと同じです。 sizeof(x)を追加すると、インクリメントは2倍になります。 sizeof(charは)間違ったすべてのものを得たように見えます。1.

1

あるので

あなたの計算は、charの罰金に動作します。例えば、PST1からのGET PST2のために、ポインタpst1はタイプst_one *であるとして、あなたは、1でそれをインクリメントする必要があるので、あなたは次のように記述する必要があり:

pst2 = (st_two*)(pst1 + 1);

を..しかし、あなたは持っている:

NP1は st_onesizeofなので、その構造がバイトを持っているとして、それはできるだけ多く st_one構造をスキップします...

pst2 = (st_two*)(pst1 + np1);

...

this oneのようなポインタ演算に関するいくつかのドキュメントを読んでください。

+0

大丈夫、それを読むでしょう - ありがとう。 – slashmais

2

C++は、追加する整数にポインタが指す要素のサイズを自動的に乗算します。これは、バイトではなく要素全体でポインタを進めたいと仮定しています。

2

CおよびC++でのポインタ演算は、ポインターのタイプが指されたsizeofを実行します。つまり、int *abc = /* ... */; int *def = abc + 1の結果はdefであり、ではなく、より先にintという結果が出ます。

longへのポインタのキャストは、実装定義の動作です。そのため、異なるマシン上で奇妙な結果が得られる可能性があります。

(この点については、ポインタ型間のキャストもあります)