0

次のコードが機能しない理由を理解しようとしています...助けてください:

void incme(double *p)
{
    printf("%x,%x\n",p,*p);
    *p = *p + 1;
    printf("%x,%x\n",p,*p);
}
int main()
{
    int i = 1;
    incme((double *)&i);    
    printf("%x,%x",&i,i);
}

出力は次のとおりです。

ff99a348,1
ff99a348,1
ff99a348,1

私は期待しています: ff99a348,1 ff99a348,2 ff99a348,2
ポインターについて知っていることはすべて壊れています...

ありがとう。

編集:

主な質問は、 incme((double *)&i); でキャストされた型について尋ねています。double にキャストして関数に渡さないのはなぜですか? ... eailer を指摘せずに申し訳ありません ....

4

3 に答える 3

3

未定義の動作のため。整数は浮動小数点ではなく、浮動小数点は整数ではありません。それに加えて、あなたはそれを見つけると思いますsizeof(int) != sizeof(double)

また、厳密なエイリアシング ルールにも違反しています。


質問とは関係ありませんが、"%p"ポインターを出力する場合は、この形式を使用する必要があります。

于 2015-08-12T08:20:41.103 に答える
2

*p = *p + 1;p beeing aを使用すると、内部で多くのことが行われますdouble*。実際、 double はカスタム形式(wiki)printfを使用して表されます。その後、整数として表示するために使用すると、このアドレスのメモリの内部表現が (double 表現に) 変更されたため、このような結果が得られます。

コードを実行したところ、次の出力が得られました。

205afc2c,205afd28
205afc2c,593b4ab0
205afc2c,0

値が double として無効であることを示しており、インクリメントされた場合、double の最初のビットは更新されませんsizeof(int)(最後の行に 0 が出力されるため)。

私が自分自身を明確にしたことを願っています!

編集

実際に何が起こるかを示すために、コードを少し変更しました。

void incme(double *p)
{
    printf("%x,%lf\n",p,*p);
    *p = *p + 1;
    printf("%x,%lf\n",p,*p);
}
int main()
{
    int i = 1;
    incme((double *)&i);    
    printf("%x, %lf, %d",&i,i, i);
}

次の出力が得られます。

cb90990c,0.000000
cb90990c,1.000000
cb90990c, 1.000000, 0

ご覧のとおり、それらを double として出力すると、値は確かに正しいです (ただし、のバイナリ表現は前に述べたとおりで1.0000はありません00000000001。これが、16 進形式で大きな数値が得られる理由です)。メインに戻ると、関数がメモリ レイアウトを変更したときに値を double (i が int であると想定される場合) として表示するとincme、1.0000 が出力されますが、このアドレスのメモリの最初の 32 ビットは0 したがって、int として出力すると 0 になります。

于 2015-08-12T08:27:26.257 に答える
0

主な理由は、printf ステートメントは次のように読む必要があります -

printf( "%p,%f", p, *p );

これにより、倍の増分が表示されます。

また、前述のように、int は通常 4 バイトで、double は 8 バイトを使用します。(ほとんどのシステムで)

于 2015-08-12T08:26:14.650 に答える