#include<stdio.h>
int main(void)
{
char c = 0x80;
printf("%d\n", c << 1);
return 0;
}
この場合、出力は-256
です。私が書くc << 0
と、出力は-128
です。
このコードの背後にあるロジックがわかりません。
#include<stdio.h>
int main(void)
{
char c = 0x80;
printf("%d\n", c << 1);
return 0;
}
この場合、出力は-256
です。私が書くc << 0
と、出力は-128
です。
このコードの背後にあるロジックがわかりません。
char
プラットフォームで署名されている可能性があります。この場合、0x80
-128を表します(2の補数を想定)。
achar
を演算子のオペランドとして使用すると、(まだ-128)<<
にプロモートされます。int
したがって、左シフトを適用すると、-256になります。技術的には、負の値のシフトは実装定義の未定義ですが、表示されるのは典型的な動作です。
すでにあなたの出発点は問題があります:
char c = 0x80;
(あなたの場合のように)符号付き型の場合、最大値を保持することが保証されている型にchar
整数定数を割り当てています。次に、コンパイラは、実装で定義された値(あなたの場合は私が推測する)を提供するか、範囲エラーを発行するかを選択できます。128
127
-128
次に、その負の値を左シフトします。これにより、未定義の動作が発生します。合計すると、いくつかの実装定義の選択肢と、結果を決定する未定義の動作があります。
char
128
選択signed char
char
int
(3つの可能性があります)int
これらすべてのケースを調べて、さまざまな結果がどうなるかを確認することは、良い練習になるかもしれません。
要約すると、いくつかの推奨事項:
char
c
が割り当てられ0x80
ます。8ビットバイトを想定すると、バイナリ表現でのその値はです10000000
。どうやら、あなたのプラットフォームでchar
は、署名されたタイプです。したがって、0x80
(つまり10000000
)は-128に対応します。
が値に<<
適用されると、char
に昇格されint
、符号が保持されます。したがって、32ビット整数で左に1回シフトすると、11111111111111111111111100000000
(2の補数)は-256になります。
補足です。ボトムアップの観点から、ビット単位のシフト(およびマスキング)は、アーキテクチャのワード長(ビットで表される)に基づいています。単語の長さは、アーキテクチャごとに異なります。
アーキテクチャ別の単語の長さについては、このWikiページを参照してください
ターゲットアーキテクチャのワード長がわかっている場合は、ビットシフトを使用して、オペランドを使用するよりも高速に乗算および除算(場合によっては)を行うことができます。
ビットシフトの興味深い図については、このWikiページを参照してください。
ビットシフトされたコードはアーキテクチャに依存するため、ビットシフトされたコードの特定の部分がアーキテクチャ間で同じように機能するとは限りません。ただし、アーキテクチャごとに単語の長さを変えるという考え方に慣れると、ビットシフトは不思議ではなくなり、予測しやすくなります。
ありがたいことに、今日では、8、16、32、および64ビットのワード長と、8ビットの文字長のみがあります。古代のコンピューティングの時代には、アーキテクチャは12、15、または23ビットのワード長(たとえば、悪意のあるもの)を持っている可能性があります。
なぜあなたのコンパイラは0x80がcharに適合しないという警告で文句を言わないのだろうか。それはあなたのプラットフォームでは-0x80から0x7Fまでの値しか表すことができない。
このコードを試してください:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
int main() {
printf("char can represent values from %d to %d.\n", CHAR_MIN, CHAR_MAX);
return EXIT_SUCCESS;
}
あなたの状況はオーバーフローと呼ばれます。