2017-02-26 1 views
4

私は自分のクイズのためにコンピュータシステムでカーネギーメロンのスライドを読んでいます。私がいないループインデックス符号なしで適切にカウントダウンする方法

unsigned i; 
for (i = cnt-2; i < cnt; i--) 
a[i] += a[i+1]; 

さらに良い

size_t i; 
for (i = cnt-2; i < cnt; i--) 
a[i] += a[i+1]; 

として符号なしを使用する
符号なし適切な方法でカウントダウンを

slide 49ページでなぜそれが無限ループにならないのかを理解してください。私はiを減らしています。それは常に符号なしですので、常にcntより小さくする必要があります。説明してください。

+0

'符号なしのi = cnt - 1;一方、(i-)a [i] = a [i + 1]; ' –

+1

@ DavidC.Rankin cとC++の安全なコーディングのRobert Seacordは、長さが単語のサイズにほぼ相当するため、後者を推奨しています。 –

答えて

2

これは、彼らは単に少し不可解i < cnti != -1のより読みやすい条件を置き換え

for (unsigned i = N; i != -1; --i) 
    ...; 

同じことを実現するために設立されイディオムの代替表現であるように思われます。 unsignedドメインで0がデクリメントされると、実際にはUINT_MAXの値にラップアラウンドされます。これは-1(符号なしドメイン内)と等しく、cnt以上です。したがって、i != -1またはi < cntのいずれかは、反復を継続するための条件として機能します。

なぜ彼らはそれを具体的に行うのでしょうか?明らかにそれらがcnt - 2から始まり、cntの値が2より小さくなる可能性があります。その場合、その条件は実際に正しく動作します(そして、i != -1はありません)。このような状況の他に、cntを終了条件に含める理由はありません。一つは、より良いアイデアはcntの事前チェック値になり、その後限りiの開始値としては非であることが知られていることをBTW i != -1イディオム

if (cnt >= 2) 
    for (unsigned i = cnt - 2; i != -1; --i) 
    ...; 

注意を、使用することを言うかもしれません負の場合、i != -1に基づく実装は、iが符号付きであるか符号なしであるかにかかわらず動作します。

+2

'i doynax

+0

@doynax:良い点。私はその詳細を逃した。 – AnT

+1

この質問には正しい候補解決策がたくさんありますが、詳細はあなたのものです。ありがとう! –

2

ループの目的は、cnt-2から0にループすることです。 i >= 0を書くことの効果を達成します。

ループの状態がi >= 0ではうまくいかない理由を前のスライドで正しく説明しています。符号なしの数値は、常に0以上であるため、このような条件は空白になります。 i < cntのループ条件は、i0を超えてラップアラウンドするまでループを終了します。符号なし0をデクリメントすると、UINT_MAX(32ビット整数の場合は2 -1)になります。その場合、i < cntはfalseであることが保証され、ループは終了します。

このようなループは書きません。それは技術的には正しいが、非常に貧弱なスタイルです。良いコードは正しいだけでなく、読みやすいので、他の人が何をしているのかを簡単に把握できます。

3

このループは、単にiが0を超えてデクリメントされ、最大のuint値になるという事実に依存しています。ループが壊れているので今はi < cnt == falseです。

Overflowing of Unsigned Intパー:

符号なし数値オーバーフローすることはできませんが、代わりにモジュロの プロパティを使用して折り返します。

CおよびC++標準では、このuintラッピング動作が保証されますが、符号付き整数では未定義です。

2

これは、符号なし整数0を減らすときに何が起こるのかを利用しています。ここでは簡単な例を示します。

生成
unsigned cnt = 2; 
for (int i = 0; i < 5; i++) { 
    printf("%u\n", cnt); 
    cnt--; 
} 

...

2 
1 
0 
4294967295 
4294967294 

符号なし整数0 - 1 UINT_MAXとなります。だから、-1を探すのではなく、あなたのカウンターが最初の状態よりも大きくなるのを見ます。

例を単純化すると、5(排他的)から0までカウントダウンすることができます。

unsigned i; 
unsigned cnt = 5; 
for (i = cnt-1; i < cnt; i--) { 
    printf("%d\n", i); 
} 

すなわちプリント:より大きいcntのでi < cntが偽であることが保証され、最終的な反復i = UINT_MAX

4 
3 
2 
1 
0 

size_tは、符号なしでC言語の最大のものよりも優れているため、cntiと同じタイプであることを確認する必要はありません。

+0

これは 'unsigned i = cnt - 1;と同じ反復を生成します。 while(i - )printf( "%u \ n"、i);しかし、* post-decrement *演算子を使って、ループの本体内で 'i = 0'を評価することができます。次のチェック(* post-decrement *の前)で 'while(0)'を返します。 –

0

あなたはint型とunsigned int型と混同していると思います。これら2つは異なっています。 intデータ型(2バイトの記憶サイズ)では、範囲は-32,768〜32,767ですが、では符号なしintデータ型(2バイトの記憶サイズ)です。範囲は0から65,535です。 上記の例では、unsigned int型の変数iを使用しています。 i = 0までデクリメントしてから、セマンティクスごとにforループを終了します。