私はLinuxが初めてです。 Ubuntu 12.04 LTSでgcc
(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3を使用します。ポインターを使用してcプログラムをコンパイルすると、次のように-Wformat
警告が表示されました。しかし、a.out
ファイルを実行すると、正しい結果が得られます。誰が私にメッセージを受け取った理由を教えて、克服するために何をすべきかを教えてもらえますか?.
私のテストプログラム:
#include<stdio.h>
void main(void)
{
int x=10,y,z;
int *p=&x ;
printf("\n\np = %u\n",p);
printf("\n*p = %u\n",*p);
printf("\n&x = %u\n",&x);
printf("\n&y = %u\n",&y);
printf("\n&z = %u\n",&z);
printf("\n&p = %u\n\n",&p);
}
出力:
qust1-Array.c:11:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:14:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:15:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:16:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
qust1-Array.c:17:2: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat]
printf()
で間違った形式指定子を使用であるため、警告が表示されます。 p
は整数ポインターです。 &p
はポインターのアドレスです。 &x
および&y
は整数のアドレスです。これらはすべてメモリ内のアドレスであり、変数の値ではありません。指定子%u
は、符号なし整数の値用です。したがって、コンパイラがオレンジを期待しているリンゴを印刷しています。アドレスは、変数に保存されている一部の値よりも短くなっています。 %u
を使用することにより、実際にはアドレス値を10進数(非常に珍しい)として出力し、その後ろにメモリ内のデータをいくつか出力します。それはおそらくあなたがやりたいことではないので、コンパイラは文句を言っています。アドレスを印刷するには、次のように指定子%p
を使用します。
printf("\n&x = %p\n",&x);
それとは別に、変数は符号付き整数なので、%i
の代わりに%u
を使用する必要があります。 printf()
の%u
形式指定子は、正の整数専用です。小さい正の値の場合、%i
と%u
は交換可能です。 変数の型が指定子と一致しないために警告が表示され、場合によっては問題が発生します。
これは、変数タイプからより賢明です:
printf("\n\np = %p\n", p); // p is a pointer so %p would print the address
printf("\n*p = %i\n", *p); // the data saved at that address is an integer
// so %i is appropriate if you dereference the
// pointer with the star "*p"
printf("\n&x = %p\n", &x); // &x gives the address of the integer variable x
// so %p is the specifier for that address
printf("\n&y = %p\n", &y);
printf("\n&z = %p\n", &z);
printf("\n&p = %p\n\n", &p); // &p gives the address, where the pointer p is
// stored -> still an address -> %p is the right
// specifier
符号付きおよび符号なしの整数とポインターのビット背景:
Cは、同じ32ビット(またはシステムアーキテクチャに応じて2の累乗)を使用して、符号なし整数と符号付き整数を格納します。 最高のunsigned int
は232-1またはバイナリ表記:
232-1 =(11111111111111111111111111111111111)2 <符号なし)
そして、ナンバーワンはバイナリで次のようになります。
1 =(00000000000000000000000000000001)2 <-(符号なし)
現在、通常の---(符号付き整数は負の数も格納する必要がありますが、32ビットの同じスペースにあります。たとえば、番号の記号を保存した場合最初のビットは、全体を少し失います。それは無駄です、例えばゼロは2つの表現を持ちます as + and-zero。この問題を回避するには符号付き整数の負の数は少し異なる方法で格納されます:符号付き整数に数値をエンコードするには、32ビット数の可能な範囲を半分に追加します。これは2です(32-1)、その新しい番号の通常のバイナリ表現を使用します。したがって、1つは2(32-1) + 1は、符号なし整数用です。我々は持っています:
2(32-1) =(11111111111111111111111111111111111)2 <-署名済み
...
1 =(10000000000000000000000000000001)2 <-署名済み
0 =(10000000000000000000000000000000)2 <-署名済み
-1 =(01111111111111111111111111111111111)2 <-署名済み
...
-2(32-1) =(00000000000000000000000000000000)2 <-署名済み
同じ数の整数をエンコードしましたが、符号付き整数の最大値は2(32-1)それを2倍にするのではなく、232-1、符号なし整数の場合。これはexcess-Kまたはoffset-binary負の数の表現と呼ばれます。ほとんどのシステムは2の補数を使用します。最初の最上位ビットが反転します。
これを確認するには、x=-1;
を設定してからprintf("%u",x)
を設定します。次の出力が得られます。
2147483648
どちらが232-1 または(01111111111111111111111111111111111)2 バイナリ表記。 2の補数の場合、この数は次のようになります。
4294967295
または232-1。これは(11111111111111111111111111111111111)に等しい2 バイナリであるため、上記の超過K値2147483648と比較して最初のビットが反転します。
つまり、これはhowデータが保存されます。 whereを考えると、ポインターが作用します。メモリ内の物理ビットにはアドレスが必要です。それらの信じられないほど多くがあるので、1ビット以上の塊でそれらに対処します。ポインタを作成すると、ポインタのアドレスにある物理メモリはメモリ内の別のアドレスを保持します。そのため、家は物理的なオブジェクトであり、PCのメモリに少し似ています。一枚の紙がポインタになります。家よりも小さいですが、家や他の家の住所を保持できます。その類推では、上記では実際の家の代わりに紙片を取り壊そうとしましたが、それは実際には山でした...