2016-08-19 4 views
11

以下に示すコードでは、何も印刷されません。つまり、forループ内の条件が失敗します。理由は何でしょうか?私は別にTOTAL_ELEMENTSを印刷するとき、それは5を与えるので'for'ループ条件が失敗するのはなぜですか?

私はそれが何かを印刷する必要がありますのでので、当然これは、5-2=3 => -1<=3でなければならない、と思いまして。

#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0])) 

int array[] = { 23, 34, 12, 17, 204, 99, 16 }; 
int main() 
{ 
    int d; 

    for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++) { 
     printf("%d\n", array[d + 1]); 
    } 

    return 0; 
} 

誰かがこのコードを説明できますか?

+0

参照:http://stackoverflow.com/questions/31361713/what-will-be-value-of-strlenstr-1-in-for-loop-condition-when-str-is-empty-in/31361751 #31361751 –

+3

"TOTAL_ELEMENTSを別々に印刷すると5となります。" - いいえ、そうではありません。あなたがそれを複雑にする理由は何ですか? – Olaf

+7

どのコンパイラを使うのか分かりませんが、GCCは適切なヒントを提供します: "警告:符号付き整数と符号なし整数の比較"。もちろん、すべての警告をオンにした場合。誰がこの8つの言葉(つまり8つの!)アップフォートを与えたのですか? – deamentiaemundi

答えて

33

これは、「通常の算術変換」の結果です。 C standardのセクション6.3.1.8から

:両方のオペランドが同じ型を持っている場合

、次いでさらなる変換が必要 ではありません。そうでない場合

、両方のオペランドが整数型を締結または両方 符号なし整数型、より少ない 整数変換ランクをよりランクのオペランド の型に変換されるのタイプのオペランドを持っている場合。符号なし整数型を持つオペランドが大きいか、または他の オペランドのタイプのランクに等しい 順位を有する場合

は、そうでない場合、は、次いで、符号付き整数型を持つオペランドが とオペランドの型に変換され符号なし整数 タイプ。そうでない場合

、符号付き整数型を持つオペランドの型は、次に符号なし整数型を持つオペランドがタイプに 変換され、符号なし 整数型とオペランドの型の値の全てを 表すことができる場合符号付き整数型のオペランド

そうでないと、両方のオペランドが符号付き 整数型のオペランドの型に対応する符号なし 整数型に変換されます。

sizeof演算子は、符号なしの値であるsize_tを返します。したがって、(sizeof(array)/sizeof(array[0])) - 2も符号なしです。

符号付きの値と符号なしの値を比較するため、符号付きの値は符号なしに変換されます。 -1を符号なしの値に変換すると符号なしの値が最大になり、その結果がfalseになります。

右側をintにキャストすると、正常に動作します。

for(d=-1;d <= (int)(TOTAL_ELEMENTS-2);d++) 

出力:

23 
34 
12 
17 
204 
99 
16 

それとも、どのようにインデックス配列正規化することで問題を回避できます。私はこのようなTOTAL_ELEMENTS - 2を印刷しようとすると

for (d = 0; d < TOTAL_ELEMENTS; d++) { 
    printf("%d\n", array[d]); 
} 
8

を:

printf("total %d\n", TOTAL_ELEMENTS - 2); 

私は行きます言って警告(GCC 4.8を使用して)T:

test.c:8:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=] 
    printf("total %d\n", TOTAL_ELEMENTS - 2); 
^

警告がTOTAL_ELEMENTS - 2long unsignedであることを意味します。今度はsigned intunsigned intを比較すると、その符号付き整数は符号なしとして扱われます。したがって、d <= (TOTAL_ELEMENTS-2)では、dは非常に高い正の値になります(2の補数システムが使用されていると仮定します)。

結果をintにキャストして問題を解決できます。

d <= (int)(TOTAL_ELEMENTS-2)

それとも、多くの場所でマクロを使用している場合、あなたはこのようにすることを変更することができます。

#define TOTAL_ELEMENTS (int)(sizeof(array)/sizeof(array[0])) 
5
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0])) 

これはunsignedタイプに評価されます。ただし、ループ内でdsignedの値です。符号付きおよび符号なしの値が関与する式では、符号付きの値は符号なしの値に変換されます。しかし、dは-1です。これは符号なしには収まらないため、マシン上の最も高い符号なしの値(2の補数)に「ラップアラウンド」します。

0

#define TOTAL_ELEMENTS(sizeof(array)/ sizeof(array [0]))は、符号なしの数値を返します。符号なしの数値に変換するため、-1が最も大きな数値になります。

"printf("%d \ n "、-1 < TOTAL_ELEMENTS);";をテストすることができます。それは0を出力しますので、私たちは前に(int)を追加することで解決することができます(TOTAL_ELEMENTS - 2)またはループを変える:

for (int d = 0; d < TOTAL_ELEMENTS; d++) { 
    printf("%d\n", array[d]); } 

そして私はd変数に依存することはないと思うdがあるので、良い方法ですforの変数。

3

これは通常の算術変換であり、sizeofを使用して取得したsize_t型はint型をsize_t型に対応する符号なし型に変換します。

私は動作がで定義された実装であることを追加したいと思います。ループは取られてもされなくてもよい。これは、size_t型の定義に依存します。

C標準では、その型size_tはint型よりも低いランクを持つことができます。その場合、整数宣伝は、型intをint型に昇格させます。その時点で両側の型はint型と同じなので、変換が停止します。次に、比較d <= (TOTAL_ELEMENTS - 2)がtrueになり、ループが実行されます。


出力は実装定義の動作に依存しているように、プログラムは、したがって、厳密に準拠していません。

関連する問題