printf で補数の動作が異なるのはなぜですか?



ビット演算子に関する章を読んでいたときに、1 の補数演算子プログラムに出くわし、それを Visual C++ で実行することにしました。


int main ()
{
unsigned char c = 4, d;
d = ~c;
printf("%d\n", d);
}

有効な出力が得られます:251


d を使用する代わりに ~c の値を保持する変数として 、 ~c の値を直接出力することにしました .


int main ()
{
unsigned char c=4;
printf("%d\n", ~c);
}

出力 -5 が得られます .


なぜうまくいかなかったのですか?


答え:


この声明では:


printf("%d",~c);

c int に変換されます 1 に入力 ~ (ビットごとの補数) 演算子が適用されます。これは整数昇格によるものです ~ のオペランドに呼び出される .この場合、unsigned char のオブジェクト タイプは (signed) int に昇格されます 、これは (~ の後) 演算子評価) printf で使用 関数、一致する %d フォーマット指定子。


デフォルトの引数の昇格に注意してください (printfとして オブジェクトはすでに int 型であるため、ここでは何の役割も果たしません。 .


一方、このコードでは:


unsigned char c = 4, d;
d = ~c;
printf("%d", d);

次のステップが発生します:



  • c 整数昇格の対象です ~ のため (上記と同様)

  • ~c 右辺値は (signed) int として評価されます 値 (例:-5 )

  • d=~c int からの暗黙的な変換を行います unsigned char へ 、 d として このようなタイプがあります。 d = (unsigned char) ~c と同じと考えてよいでしょう。 . d に注意してください 負にすることはできません (これはすべての符号なし型の一般的な規則です)。

  • printf("%d", d); デフォルトの引数昇格を呼び出します 、したがって d int に変換されます (負でない) 値は保持されます (つまり、int 型は unsigned char のすべての値を表すことができます タイプ)



1) int と仮定 unsigned char のすべての値を表すことができます (以下の T.C. のコメントを参照)、しかしそれは とても このように起こりやすい。より具体的には、 INT_MAX >= UCHAR_MAX と仮定します 保持します。通常は sizeof(int) > sizeof(unsigned char) ホールドとバイトは 8 ビットで構成されます。それ以外の場合は c unsigned int に変換されます (C11 節 §6.3.1.1/p2 による)、および書式指定子もそれに応じて %u に変更する必要があります。 UB を取得しないようにするため (C11 §7.21.6.1/p9)。