2012-03-28 7 views
0

可能な重複は:
Confused about C macro expansion and integer arithmetic
Cコードに続く問題は何ですか?

A riddle (in C)

以下Cプログラムの予想される出力は、アレイ内の要素を印刷することです。しかし、実際に走っても、それはしません。

#include<stdio.h> 

    #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

間違いはありますか? –

+0

どのようにデバッグを試みましたか?例えば、TOTAL_ELEMENTSの価値を印刷しようとしましたか? –

+0

http://codepad.org/n814mOIf –

答えて

6

sizeofがあなたに与え、あなたはおそらく気づいているだろう符号なし値は、あなたの(a)などgcc-Wall -Wextraを使用して、警告レベルを上げていたので:

xyzzy.c: In function 'main': 
xyzzy.c:8: warning: comparison between signed and unsigned 

署名を強制すると、正常に動作します。

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

詳細については、ISO規格から詳細を確認することができます。異なるタイプ間の比較では、タイプを互換にするためにプロモーションが実行されます。選択される互換性のあるタイプは、符号の互換性、精度およびランクなどのいくつかの要因によって異なりますが、この場合は符号なしタイプsize_tが互換タイプであるとみなされ、dがそのタイプにアップグレードされました。

残念ながら、-1を符号なしタイプ(少なくとも2の補数ではほぼ確実に使用しています)にキャストすると、正の数がかなり大きくなります。

5より確かに大きなものは(TOTAL_ELEMENTS-2)です。言い換えれば、あなたのための文では、効果的に次のようになります。

for (d = some big honking number way greater than five; 
    d <= 5; 
    d++ 
) { 
    // fat chance of getting in here !! 
} 

(a)のextraを使用するには、この要件gcc開発者と私の間の競合のポイントのまま。彼らは明らかに私が以前に気付いていなかった(すべてダグラスアダムスに謝罪した)単語allの新しいの定義を使用しています。

+0

私はprogrammin言語の新人です。だから私はこのコードで何が間違っているのか知りません。あなたは訂正をお勧めしますか? – Parag

+0

@Parag、私はあなたに訂正をしました。これは、sizeof式の結果を符号付きの型にキャストしています。 – paxdiablo

+0

これは私のforループが(d = -1; d <=(int)(TOTAL_ELEMENTS-2); d ++)のようになることを意味します。 – Parag

0

TOTAL_ELEMENTSのタイプはsize_tであり、コンパイル時に2を減算するので、5UL(符号なしサフィックスを強調)です。 整数dとの比較は常にfalseです。コードをコンパイルしようとすると、インテルコンパイラはFTWを正確に警告します。

+0

注:gccは、符号付き/符号なし比較については警告しません。 '-Wall'では警告しません。 '-Wextra'を指定する必要があります。 –

0

何が問題になったかを明確にするために、sizeof()はsize_tという結果の型に変換されます。これは符号なし整数で、unsigned int以上です。

したがって、(sizeof(array)/sizeof(array[0]))の結果は、size_t型の2つのオペランドの結果になります。除算は次のオペランドで実行されます。size_t/size_t。どちらのオペランドも同じ型ですので、うまく動作します。除算の結果はで結果をTOTAL_ELEMENTSタイプであり、タイプsize_tである。

発現(TOTAL_ELEMENTS-2)2整数リテラルはint型であるので、したがって、タイプsize_t - intを有します。

ここでは、2種類のタイプがあります。コンパイラが2つの異なるタイプにスポットを当てたときに起きる(正式には「通常の算術変換」)のバランシングと呼ばれるものが発生します。バランシング規則では、一方のオペランドが署名され、他方が符号なしであれば、署名されたものは暗黙のうちに暗黙的に符号なしの型に変換されると述べている。

これはこのコードで発生します。 size_t - intsize_t - size_tに変換された後、減算が実行され、結果はsize_tになります。その後int <= size_tsize_t <= size_tに変換されます。変数dは符号なしに変わり、負の値を持つ場合はコードがひどくなります。

+0

"一方のオペランドが署名され、他方が署名されていない場合、署名されたものは暗黙のうちに暗黙的に符号なしの型に変換されるというバランシング規則には、かなり正確ではありません。符号なしタイプが符号付きよりもランクが小さく、符号なしタイプのすべての値が符号付きタイプで表される場合、符号なし値は符号付きタイプに変換されます。完全性のためにここには適用されません。 –

+0

@DanielFischer私は意識して、すべての "ifs&buts"を意図的に削除しました。私はOPがすべての整数プロモーションと通常の算術変換ルールの詳細な説明に役立たないと思う。 – Lundin

+0

ええ、私の内側のパンツはちょうどそれを言及すべきだと思った。 –

関連する問題