9

このサンプルコードを本で見つけたのですが、printf文の式がわかりません。このプログラムは正常にコンパイルされ、出力は 4 になります。

void main(){
    unsigned char c;

    typedef struct name {
      long a;
      int b;
      long c;
    }r;

    r re = {3,4,5};
    r *na=&re;

    printf("%d",*(int*)((char*)na + (unsigned int ) & (((struct name  *)NULL)->b)));
}
4

3 に答える 3

9

最後の行から始めましょう:

printf("%d",*(int*)((char*)na + (unsigned int ) & (((struct name  *)NULL)->b)));

解釈しましょう:

(unsigned int ) & ((    (struct name  *)NULL)->b )

実際に にキャスト& (( (struct name *)NULL)->b )していunsigned intます。

& (( (struct name *)NULL)->b )アドレスです(つまり、ポインタを提供します):

((  (struct name  *)NULL)->b )

これは実際にはNULL (0) からのb(as ) のオフセットであり、4 バイト (aが 4 バイトであると仮定) であり、int のポインターに変換されると、2 ( 2 バイトであると仮定) になります。name.blongint

代わりにNULLへのポインターだった0xFFFF0000場合は、 に&(ptr->b)なります0xFFFF0002。しかし、それはもっと&(0 -> b)そう0x00000002です。

つまり、(unsigned int ) & (( (struct name *)NULL)->b ) == 2(マシンによっては 1 つ、または 4 つかもしれません)。

残りは簡単です:*(int*)((char*)na + 2を指しre->bます。したがって、4 (コードで初期化されたものr re ={3,4,5};) が出力されます。

PS: (unsigned int ) & (( (struct name *)NULL)->b ) != 2(おそらく 1、4、または 8 の場合でも) - 同じオフセットを使用して値を取得するため、4 を出力する必要があります。

于 2014-11-13T09:22:27.447 に答える
4

rer型のローカル変数ですstruct name。通常、コール スタックに割り当てられます。

naへのポインタreです。

(unsigned int) & (((struct name *)NULL)->b)未定義の動作かもしれませんが(確かではありません)、ほとんどのコンパイラはそれをフィールドのオフセット (バイト単位) にコンパイルしますb(同様に、 offsetof(3)offsetofを参照)。私のマシンでは8かもしれません。

(char*)na + 上記のオフセットは、多くの場合、&re.b

そのポインターを逆参照します。これは実際には&re.b

あなたのコードは標準に準拠していない可能性があると思います(いくつかの議論についてはこの回答NULLを参照してください。すべてゼロビットの単語ではない架空のマシンとCの実装があるかもしれません。そのような実装は知りません)が、私が知っているすべてのマシンでについて、フィールドの値を出力する必要がありますre.b

于 2014-11-13T09:18:23.317 に答える
4

コード:

(unsigned int ) & (((struct name  *)NULL)->b))

struct name変数の先頭からの距離をバイト数で取得することを目的としていますb

これを行う標準的な方法があります: offsetof(struct name, b); . このコードを書いた人はoffsetof、.

コードは null ポインターを逆参照することで未定義の動作を引き起こしますが、一般的なコンパイラーはエラーをトリガーせずにそれを受け入れる場合があります。これはおそらく、コンパイラー開発者がこのような既存のコードが存在することを知っているためです。


コードの残りの部分は簡単です。構造体の先頭を指します。そのバイト数だけ進み、その場所から int を読み取ります。bもちろん、直接読むことと同じです。

于 2014-11-13T09:38:30.980 に答える