簡體   English   中英

在倒計時循環中使用 size_t 時的無限循環

[英]Infinite loop when using size_t in a count down for loop

所以我在任何索引 for 循環中使用size_t而不是int來防止負索引。 但是在倒計時時,這會導致溢出:

for (size_t i = 10; i >= 0; --i) {
    // Do something, f.ex. array[i] = i
}

什么是防止這種情況的好方法?

  • 使用int代替?
  • 使用 i == 0 作為終止條件? (但是,如果我需要 0,這將不起作用)

我很感激任何反饋!

for (size_t i = 10; i <= 10; --i) // do something

當溢出 do 發生時,它將四舍五入到最大的整數,因此條件將失敗。

for (size_t i = 11; i-- > 0; ) {
    // Do something, f.ex. array[i] = i
}

注意:問題以 value=10 開始循環(這很奇怪,但並非不可能)。 我從11開始,但是第一次進入循環體時,它已經遞減到10了。

從技術上講,這不是溢出,因為size_t是無符號類型,但它絕對是無限循環,因為終止條件始終為真。

無符號整數在0遞減時回繞 請注意,您的循環將在環繞發生之前運行11次,而不是10

在遞減索引之前,您必須檢查條件。 以比最大有效索引大 1 的初始值開始枚舉可提高視覺一致性並簡化測試。

這是一個更正的版本,您可以看到i的初始值是數組的元素數:

int array[11];
for (size_t i = 11; i-- > 0; ) {
    // Do something, f.ex. array[i] = i
}

慣用的方式,雖然不是每個人的口味,是使用幻燈片運算符:

for (size_t i = 10 + 1; i--> 0; )

它並不是真正的運營商,但這就是多年來人們所熟知的。

最簡單的方法是增加上限值。 例如

const size_t N = 10;

for (size_t i = N + 1; i != 0; --i) {
    // Do something, f.ex. array[i-1] = i-1
}

或者

const size_t N = 10;

for (size_t i = N + 1; i-- != 0; ) {
    // Do something, f.ex. array[i] = i
}

在一般情況下,當 i 可以等於存儲在size_t類型的對象中的最大值時,您可以使用以下技巧

#include <stdio.h>

int main( void )
{
    const size_t N = 10;

    for (size_t i = N, j = N; !( i == 0 && j == -1 ); j--)
    {
        i = j;
        printf( "%zu ", i );
    }

    printf( "\n" );
}

否則,您可以使用 do-while 循環。 在這種情況下更合適。 例如

size_t i = N;

do
{
    printf( "%zu ", i );
} while ( i-- != 0 );

size_t i = 10; i >= 0; 永遠不會為假,因為size_t是某種無符號類型並且所有值都大於或等於零。

... size_t這是sizeof運算符結果的無符號整數類型; ...
C11 §7.19 2

啟用警告的良好編譯器會對此發出警告。
希望這種無限循環永遠不會發生,因為對警告的調查會首先糾正問題。


最佳選擇取決於編碼目標

好的代碼會避免像 10 這樣的幻數。最好是代碼派生出來的。 在這個簡單的例子中,它應該是 11。

#define A_SIZE 11
int array[A_SIZE];
...
for (size_t i = A_SIZE; i-- > 0; ) {
    // Do something, f.ex. array[i] = i
}

OTOH,代碼可能在循環中有break條件,需要在后面的代碼中使用i來指示array[]用法

size_t i = A_SIZE;
while (i > 0) {
  if (...) break; 
  i--;
  // Do something, f.ex. array[i] = i
  if (...) break; 
}
// Do something with i

代碼可能有一個合同要求在不同的地方使用10

// Contract says loop must handle indexes 0 to N, inclusive
#define N 10
int array[N + 1];

for (size_t i = N; i + 1 > 0; i--) {
  // Do something, f.ex. array[i] = i
}

好的優化編譯器不會對每個i + 1 > 0執行+1 ,而是創建等效的高效代碼。

代碼是一種最能傳達代碼整體含義的時尚。

問題是在您的實現中 size_t 的類型為unsigned longunsigned int

當 i=0 條件完成並且 --i 將其轉換為 4294967295UL = ULONG_MAX,因此循環中的測試條件i >= 0永遠不會為 false 。

size_t 有一些無符號類型,我永遠不會是負數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM