次のプログラムでは
#include<stdio.h>
int main()
{
char i=0;
for(i<=5 && i>=-1;++i;i>0)
printf("%d\t",i);
return 0;
}
「i」は 1 から 127 まで、次に -128 から -1 まで出力されます。
これはなぜですか?
次のプログラムでは
#include<stdio.h>
int main()
{
char i=0;
for(i<=5 && i>=-1;++i;i>0)
printf("%d\t",i);
return 0;
}
「i」は 1 から 127 まで、次に -128 から -1 まで出力されます。
これはなぜですか?
これは、私がこれまでに見た中で最も不正な for ループであるに違いありません。for ループは次のようにフォーマットされます。
for ( initalization; condition; update )
for
ループの開始時にinitialization
発生します。これは通常、 のようなものi = 0
です。各ループの先頭で、condition
(通常はのようなものi < 5
) が評価され、ループを続行する必要があるかどうかを確認し、ループを続行する必要がある場合は、update
が実行され (通常はのようなもの++i
)、ループがもう一度実行されます。
ここで起こっていることは、ループが条件として使用されているため、 が値に評価された++i
ときにのみ終了するため、 から開始して から のオーバーフローまでインクリメントし、 に達するまでインクリメントを続け、その時点で と に評価されます。ループは終了します++i
0
1
char i
128
-127
-1
++i
0
編集
したがって、あなたのコードによればi<=5 && i>=-1
、ループの最初の繰り返しの最初に実行され(これはまったく何も達成されません)、++i
ブール値の状態が評価されます(これは0
開始され、事前インクリメントを使用すると、評価は1
したがって、0
ブール値が通過するわけではありません)、次にexecutesのupdate
セクションがi>0
実行されますが、これも何もしません。
EDIT2
あなたの質問が本当になぜそれが起こるのかについてであるなら1,2....128,-127,-126....-1
、ヨアヒムはその行動について非常に良い説明を提供しました
朗報: あなたの実装でchar
は、署名されています!
また、i
127 は signed に収まる最大の正の値であるため、 の値が 127 から -128 にオーバーフローしchar
ます。
編集:実際には、実装の署名についてはわかりませんchar
が、ループは完全に壊れています:
それはおそらく
for (i = 0; i <= 5; i++)
しかし、それは単なる推測です。解釈するのは難しいです。
Achar
は、コンパイラの符号付き 8 ビット整数です。-128 から +127 までの値を表すことができます。ループ終了条件は++i
であり、C ではゼロ以外の値はすべて true と見なされるため、++i
is が 0 になるまでループしi
ます-1
。
if が 127 から -128 になる理由は、符号付き整数がコンピューターでどのように機能するかによるものです。127 のバイナリ ビットは01111111
で、-128 のビット パターンは です1000000
。に 1 を追加する01111111
と、 になり10000000
ます。
全体として、for
ループは意味がありません。構文的には正しいですが、意味がありません。for ループがどのように機能するかの説明については、Dan F による回答を参照してください。
2 の補数表現について読みたいと思うかもしれません
プログラムは、出力時に "i" を 8 ビットの符号付き整数として解釈します。つまり、符号に 1 ビット、データに 7 ビットを意味します。これにより、有効な値の範囲は -128 から 127 になります。
「for」ループは、printf の前に i をプリインクリメントするため、最初のパスの値は 1 になり、インクリメントは i+1=128 まで続きます。これにより、符号付き整数の符号ビットが反転し、++ までループが実行されます。 i は i を 0 にします。
余談ですが、その for ループはひどいものです。あなたはそれがはずであることを知っていますよfor(intialisation; end condition; increment)
ね?
ともかく。i は 0 に初期化されます。forループの最初のラウンドは、事前インクリメントを持つ終了条件(++i)をテストしています。したがって、i は 1 にインクリメントされ、ループが実行されて 1 が出力されます。
今繰り返します。各ループは、終了条件テストが i を事前にインクリメントしているため、i に対して 1 つ高い値を出力します。
最終的には 127 に達します。その後、128 に増加しますが、符号付き整数を期待する "%d" として出力しているため、2 の補数を使用すると、これは -128 と解釈されます。
その後、インクリメントは 255 まで続きます (-1 として出力されます)。次のプレインクリメントでオーバーフローが発生するため、i は再び 0 になり、その時点で「終了条件テスト」が false と評価され、ループが停止します。
このプログラムでは、for ループが非常に奇妙に使用されています。「i<=5 && i>=-1」をチェックしてループ変数を初期化します。代入は行われません。ループ中に、i = -1 になるまで真である条件「++i」を評価します。増分ステップでは、数値がゼロより大きいかどうかを確認するだけです。
あなたは実際に次のことを行います:
for(i = 1; i != 0; i++)
{
printf("%d\t",i);
}
127 を超えるオーバーフローでは、1 から 127 および -128 から -1 の数値が得られます。