Почему условие цикла 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
.