2016-08-19 3 views
11

В приведенном ниже коде ничего не печатается, что означает, что условие в цикле 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; 
} 

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

+0

См. Http://stackoverflow.com/questions/31361713/what-will-be-value-of-strlenstr-1-in-for-loop-condition-when-str-is-empty-in/31361751 # 31361751 –

+3

"Потому что, когда я печатаю TOTAL_ELEMENTS отдельно, это приводит к 5" - Нет, это не так. Любая причина, по которой вы так усложняетесь? – Olaf

+7

Я не знаю, какой компилятор вы используете, но GCC дает вам правильный намек: «предупреждение: сравнение между подписным и беззнаковым целым». Конечно, если вы включили все предупреждения. Кто дал это 8 (на словах: восемь!) Upvotes? – deamentiaemundi

ответ

33

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

Из раздела 6.3.1.8 в C standard:

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

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

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

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

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

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

Поскольку вы сравниваете значение signed и unsigned, значение signed преобразуется в 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]); 
} 
8

Когда я пытаюсь напечатать 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])) 
5
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0])) 

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

0

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

3

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

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

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


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

Смежные вопросы