#define address (*((unsigned int *)10))
void main()
{
unsigned int *p;
p = &(address);
}
'p' の値は 10 です。上記の式はどのように評価されますか? 一番内側のブレースから一番外側のブレスに向かってじゃないですか?しかし、そうである場合、「&」には意味をなさない左辺値があります。10 に評価される &*(10) に変換されることはわかっています。
要するに
p = &(0)
コンパイル中じゃないの?
いいえ、まったく違います。コンパイラは、アドレス 10 に値 0 があることを知りません。
これは非常に移植性が低く、おそらくaddress
メモリ内の定義された場所から値を読み取るために使用できる便利な識別子を提供することになっています。組み込みプログラミングから来ていると思います。
address
は、アドレス 10 にある変数として解釈される可能性がunsigned int
あり、そのアドレス - 10 - は によってのみ要求できるため、スペルが間違っています&address
。
多くの場合、理解していないことに取り組んでいるときに、これを一度に 1 歩進めるのが最も簡単です。あなたはあなたの質問で正しい軌道に乗っています:
一番内側のブレースから一番外側のブレスに向かってじゃないですか?
それでは、そこから始めましょう。マクロの最も内側の中括弧にあるものを取得すると、((unsigned int *)10)
それは何をしますか? このステートメントは、リテラル value10
を unsigned int へのポインターに型キャストします。これで、アドレス 10 へのポインターができました。@glglgl が述べたように、マクロの名前が不適切です。マクロをアドレスにしたい場合は、ここで終了します。これは組み込みプログラミングでよく使用される手法で、アドレスが何に使用されているか (特定のペリフェラル レジスタなど) を正確に知ることができます。
次の中かっこのセットは、(*((unsigned int *)10))
型キャストしたばかりのポインターを逆参照します。したがって、マクロは実際には address に現在格納されている値を提供しています10
。
最後に、値を pointer に代入するときはp = &(address);
、 address に格納されている値のアドレス10
、つまり 10 を取得するだけです。同じように簡単に述べp = (unsigned int *)10;
て、同じ結果を得ることができます。
void main()
する必要がありますint main(void)
。使用するように指示された本やチュートリアルはvoid main()
、C 言語をよく知らない人によって書かれています。
マクロ展開後の本体はmain
次と同等です。
unsigned int *p = &(*((unsigned int *)10));
単項演算子のオペランドが単項演算&
子の結果である場合*
、両方の演算子は省略されます (これは標準で明示的に述べられています)。したがって、上記は次と同等です。
unsigned int *p = (unsigned int *)10;
これはint
値を取り、それを からに10
変換します。int
unsigned int*
整数からポインタへの変換の結果は実装定義ですが、「実行環境のアドレッシング構造と一致することを意図しています」。
したがって、「メモリ アドレス 10」という考えが理にかなっている場合、上記はおそらくそのアドレスに設定p
されます。
結果のポインターが正しく配置されていない可能性があります。多くのシステムでは、unsigned int
は 4 バイトであり、4 バイトのアラインメントが必要です。10 は 4 の倍数ではありません。
コードは意図的に難読化されているようです。簡略化されたバージョンはより単純であり、役に立たない可能性があります。
万一unsigned int
、システムのアドレス 10 にオブジェクトがあり、それにアクセスする必要があることがわかっている場合は、
unsigned int *p = (unsigned int *)10;
やり方だろう。