web-dev-qa-db-ja.com

補完機能が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になります。

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

57
Sanketssj5

charは、2番目のスニペットの操作~の前にintステートメントでprintfに昇格されます。つまり、c、つまり

0000 0100 (2's complement)  

バイナリで昇格(32ビットマシンを想定)

0000 0000 0000 0000 0000 0000 0000 0100 // Say it is x  

そのビット単位の補数は、値の2の補数から1を引いたものに等しい(~x = −x − 1

1111 1111 1111 1111 1111 1111 1111 1011  

これは、2の補数形式の10進数の-5です。

charcからintへのデフォルトの昇格は、

d = ~c;

補数演算の前ですが、dunsigned char型であるため、結果はunsigned charに変換されます。

C11:6.5.16.1単純な割り当て(p2):

単純な代入(=)では、右のオペランドの値が代入式の型に変換され、左のオペランドで指定されたオブジェクトに格納されている値を置き換えます。

そして

6.5.16(p3):

代入式のタイプは、左辺値変換後の左オペランドのタイプです。

27
haccks

~演算子をcに適用すると、intに昇格され、結果もintになります。

その後

  • 最初の例では、結果はunsigned charに変換され、次にsigned intにプロモートされて出力されます。
  • 2番目の例では、結果はsigned intとして出力されます。
12
alk

それはop -5を与えます。なぜうまくいかなかったのですか?

の代わりに:

printf("%d",~c);

使用する:

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

最初の例と同じ結果が得られます。

~オペランドは整数の昇格を受け、デフォルトの引数の昇格は可変個関数の引数に適用されます。

10
ouah

標準からの整数昇格:

符号付き整数型のオペランドの型が、符号なし整数型のオペランドの型のすべての値を表すことができる場合、符号なし整数型のオペランドは、符号付き整数型のオペランドの型に変換されます。

8
David Ranieri