質問
Cで、私はいくつかの機能の変数とアドレスのアドレスをプリントアウトしようとしました。 私は、一方が他方が正の値で、負の値であるなりました。 私の質問は:なぜCは全て負または全て正の値で表しているわけではありません。
?ここに私のコードは次のとおりです。
int foo() {
return 0;
}
int main() {
int a;
printf("%d\n",&a);
printf("%d\n",foo);
return 0;
}
ここでの結果は次のとおりです。
-1075908992 134513684
解決
メモリアドレスは、その方法で符号付き整数として解釈されるべきではありません。数の符号は最上位ビットのセットので、32ビットシステムでは0x80000000上記メモリアドレスが負になり、(現在使用中のシステムの大部分で使用される2の補数表現を仮定する)、およびメモリに依存します0x80000000から以下のアドレスは正となります。それには本当の意味はありません。
あなたは%p
修飾子を使用してメモリアドレスを印刷する必要があります。代わりに、一部の人々は(64ビットシステム上または%08x
)メモリ・アドレスを印刷するため%016llx
を使用しています。これは常に符号付き10進数の整数よりもはるかに有用であり、16進数の符号なし整数として出力します。
int a;
printf("%p\n", &a);
他のヒント
ほとんどの標準が可能準拠であるためには、printf()
とvoid*
の引数をキャストするためのフォーマット文字列に「%pを」渡します。
printf("%p\n", (void*)&a);
printf("%p\n", (void*)foo);
ドラフト規格(n1401.pdf)から引用
7.20.6.1 The fprintf function 8 The conversion specifiers and their meanings are: p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
あなたはポインタフォーマッタを渡す必要があります:
printf("%p\n",foo);
あなたは小数でプリントアウトしています。あなたは、おそらく(ほとんどのメモリアドレスは、慣例により、16進数で表示されます)。
(「%pを」使用)を16進数でメモリ位置をプリントアウトしたいですどちらも、ポインタは符号を持っていませんが、符号付き整数に変換するとき、それが正または負であるかもしれない。
なお、整数を印刷するように設計されたフォーマットの変数とprintf
へのポインタを渡すと未定義の動作を引き起こします。あなたは、常に明示的(キャストによって異なります)、不特定または実装定義された動作を取得するために、正しい型にキャストする必要があります。
ポインタがはるかに符号なし整数のようなもの、整数を署名されていません。彼らは符号付き整数であるかのようにしかし、あなたはそれらをプリントアウトしています。 int
、unsigned int
、float
、およびポインタ:32ビットシステムでは、32ビット長である可能性が高いいくつかあります。あなたは、一般的に、これらはちょうどそれらを見て、である言うことができない、それらはすべて異なるものを意味します。 (実験として、あなたは様々な整数を渡すことができますし、フロートとその逆のようにそれらを印刷:。それは、一般的に悪い習慣だが、それは、異なるデータ型が異なることを意味するかということをお見せすることができます)。
可変個の引数(「可変引数」機能を)取る機能は、道の複雑な並べ替えで行います。特に、それらは、引数の型をチェックしません。あなたが同様の機能をprintf()
としたい任意の引数を渡すが、書式指定子に一致するようにそれらを取得することは問題であることができます。これは、関数が(それはあなたがfloat
のような関数にint foo(int)
を渡されたかのように)タイプ権を取得する方法がないことを意味します。
引数の間違った種類を渡すと、未定義の動作につながる、とあなたは間違ったサイズの引数を渡す場合は問題につながることは特にそうです。ほとんどの64ビットシステムでは、ポインタは64ビットであるとint
sは32である。
そのため、あなたはフォーマット文字列に正しいことを使用する必要があります。 printf("%p", &a);
は、あなたが望むものであるポインタとしてa
のアドレスを出力します。標準はprintf("%p", (void *)&a);
のようなものを必要としますが、任意のコンピュータ上の不要なのです実際問題として、あなたがこれまでに発生する可能性があります。
また、同様printf("%p", &a)
を使用することができます。 %p
は実装定義された方法におけるポインタの値を出力する、ポインタのフォーマット指定です。実際に、話す%Xとしてそのほとんど同じですが、ポインタがintよりも大きい場合を扱うでしょう。
printf関数は、いくつかの魔法の解釈ツールではありません。それはあなたがそれを与える場合は「%d」をやっているすべては、その変数に座っビットパターンが整数としてどのように見えるかを示すされます。
いくつかのポインタがマイナスといくつかの肯定的である理由としては、それは意味の全ては、いくつかは、上位ビットがセットされていると、一部にはないということです。どのようなアドレスオブジェクトに与えられていること(通常はいくつかのハードウェアの助けを借りて)お使いのオペレーティングシステムの本当に唯一のビジネスです。プログラミング言語は、それには、実際の発言権を持っていません。
私があなただったら、、私はそのようにアドレスをプリントアウトされません。あなたが実際にそれらを見て必要性を感じた場合は、代わりに「%d個」の「X%」を使用。すなわち、それははるかに簡単であり、どれがされていないビットを把握することができた、六角でそれらを印刷します。彼らは0かそうでないならば、彼らはいくつかの他のアドレスの値と一致した場合Generalyあなたがアドレスを気にしようとしているすべてのです。
別に%p
を使用してから、あなたもunisgned整数を取得することを確認するためにuintptr_t
にキャストできます。
正しい形式指定子を取得する(16進数またはPRIuPTR
)フォームPRIXPTR
を<inttypes.h>
を使用します。
printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo);
次のコードを使用します:
printf("%u",&a);