Почему условие цикла for for не работает?

В приведенном ниже коде ничего не печатается, что означает, что условие в цикле for не выполняется. В чем может быть причина?

Мне интересно, потому что, когда я печатаю TOTAL_ELEMENTS отдельно, он дает 5, поэтому, естественно, это должно быть 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;
}

Может кто-нибудь объяснить этот код?

Ответ 1

Это результат "обычных арифметических преобразований".

Из раздела 6.3.1.8 стандарта C:

Если оба операнда имеют один и тот же тип, то дальнейшее преобразование не будет необходимо.

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

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

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

В противном случае оба операнда преобразуются в unsigned целочисленный тип, соответствующий типу операнда со знаком целочисленный тип.

Оператор sizeof возвращает size_t, который является значением без знака. Таким образом, (sizeof(array) / sizeof(array[0])) - 2 также не имеет знака.

Поскольку вы сравниваете значение signed и unsigned, подписанное значение преобразуется в unsigned. Преобразование -1 в unsigned приводит к наибольшему значению без знака, что приводит к тому, что сравнение является ложным.

Если вы нажмете правую сторону на int, она будет работать как ожидалось.

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

Вывод:

23
34
12
17
204
99
16

Или вы могли бы избежать проблемы, нормализовав, как вы индексируете массив:

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

Ответ 2

Когда я пытаюсь напечатать TOTAL_ELEMENTS - 2 следующим образом:

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

Я получил предупреждение (используя gcc 4.8), говорящий:

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 - 2 - long unsigned. Теперь, когда вы сравниваете signed int с unsigned int, подписанный int обрабатывается как unsigned. Таким образом, в d <= (TOTAL_ELEMENTS-2), d становится очень высокоподвижным положительным числом (при условии, что используется 2 системы с номерами дополнений).

Вы можете отправить результат на int, чтобы исправить проблему.

d <= (int)(TOTAL_ELEMENTS-2)

Или, если вы используете макрос во многих местах, вы можете изменить это следующим образом:

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

Ответ 3

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

Это оценивает тип unsigned. Однако в вашем цикле d есть значение signed. В выражении, где участвует подписанное и неподписанное значение, подписанное значение преобразуется в unsigned. Но d равно -1, которое не может быть помещено в unsigned, поэтому оно "обертывается" до самого высокого значения без знака на машине (на 2 дополнения).

Ответ 4

Как уже объяснялось другими ответами, причиной являются обычные арифметические преобразования, тип size_t, полученный с помощью sizeof, приводит к тому, что int преобразуется в неподписанный тип, соответствующий типу size_t.

Я хотел бы добавить, что поведение определяется реализацией 1. Цикл можно взять или нет. Это зависит от определения типа size_t.

Стандарт C допускает, что тип size_t имеет более низкий ранг, чем тип int. В этом случае целые рекламные акции способствуют типу size_t для ввода int. В этот момент обе стороны имеют один и тот же тип int, поэтому конверсии прекращаются. Затем сравнение d <= (TOTAL_ELEMENTS - 2) дает true, и цикл берется.


1 Поэтому программа не является строго соответствующей, так как вывод зависит от поведения, определенного реализацией.

Ответ 5

Вы знаете #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.