Подтвердить что ты не робот

Петля, начинающаяся с -1, ничего не печатает

Эта программа должна печатать элементы array, но когда она запущена, вывод не выводится.

#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;
}

Почему эта программа не показывает какой-либо вывод?

4b9b3361

Ответ 1

sizeof возвращает целое число без знака, поэтому TOTAL_ELEMENTS также не имеет знака.

d. Первоначально d - -1. Однако при выполнении сравнения d неявным образом выводится без знака, поэтому при сравнении с TOTAL_ELEMENTS он больше не -1, он фактически UINT_MAX (который является 4294967295 на моей машине, но может отличаются для других).

Кроме того,

Если вы хотите исправить это, введите TOTAL_ELEMENTS в int:

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

Это напечатает:

23
34
12
17
204
99
16

Как и следовало ожидать. Вы также можете посмотреть операцию сравнения для целых чисел без знака и знака для получения дополнительной информации о теме сопоставлений без подписей.

Стоит отметить, что включение предупреждений компилятора помогло бы вам разобраться в происходящем (как это заметил hyde в comment):

$ gcc -Wall -Wextra test.c
test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 
              ~ ^ ~~~~~~~~~~~~~~
1 warning generated.

В качестве альтернативы, почему бы не начать d в 0 и вместо этого перейти на TOTAL_ELEMENTS - 1? Вы даже можете отказаться от приведения типа, который необходим только для углового случая d = -1.

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

В качестве сноски приведены соответствующие стандартные отрывки C99:

  • 6.3.1.8p2 определяет преобразование из подписанного типа без знака.

    Если операнд, который имеет целочисленный тип без знака, имеет ранг, больший или равный рангам типа другого операнда, тогда операнд со знаком целочисленного типа преобразуется в тип операнд с целым числом без знака.

  • 6.3.1.3p2 определяет, как выполняется преобразование: добавив UINT_MAX + 1 в подписанное представление.

    Если новый тип без знака, значение преобразуется путем многократного добавления или вычитания более одного максимального значения которые могут быть представлены в новом типе, пока значение не будет в диапазон нового типа.

    So -1 = > -1 + (UINT_MAX + 1)= UINT_MAX, для этого сценария.

Ответ 2

My gcc выводит это предупреждение:

warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 

что означает, что (TOTAL_ELEMENTS-2) есть unsigned int, а d - signed int. Это делает выражение всегда false для начального значения d, так как (unsigned int)(-1) > (TOTAL_ELEMENTS-2).

Ответ 3

Двоичные операции между различными типами интегралов выполняются в "общем" типе, определяемом так называемыми обычными арифметическими преобразованиями. Таким образом, int d имеет одинарный тип, инициализированный значением -1. Который при преобразовании в unsigned int возвращает максимум unsigned int, который намного больше, чем значение, возвращаемое TOTAL_ELEMENTS.