длинная без знака 0 <-1? - PullRequest
       0

длинная без знака 0 <-1?

8 голосов
/ 12 сентября 2009

Я этого не понимаю!

#include <stdio.h>

int main()
{
    unsigned short t1 = 0, t2 = 0;

    if( t1 < t2-1 )
        printf(" t1 < t2-1\n");

    unsigned long s1 = 0, s2 = 0;

    if( s1 < s2-1 )
        printf(" s1 < s2-1\n");
}

это приводит к:

 s1 < s2-1

Либо оба должны потерпеть неудачу, либо оба нет. Я пробовал это с gcc 4 & 4.2

Ответы [ 4 ]

13 голосов
/ 12 сентября 2009

Я не уверен, но подозреваю, что выражение t2-1 автоматически расширилось до значения int. У меня нет стандарта c, каковы точные правила преобразования, но я считаю, что типы, меньшие, чем int, автоматически расширяются.

12 голосов
/ 13 сентября 2009

Язык C выполняет «Обычные арифметические преобразования» для многих операторов - преобразования описаны в 6.3.1.8 стандарта C99. Для целочисленных операндов выполняются первые рекламные акции, и это является причиной вашей проблемы. Акции описаны в 6.3.1.1 (Арифметические операнды / булевы, символы и целые числа), в которых, среди прочего, сказано:

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

Повышение применяется только к объектам или выражениям с целочисленным типом с рангом меньше int и unsigned int (или битовых полей).

Итак, в вашем выражении:

t1 < t2-1 

даже если переменные unsigned short, они повышаются до int, поскольку на вашей платформе int может представлять все значения unsigned short. Таким образом, выражение оценивается с использованием int типов, и не происходит никакого переполнения - часть выражения t2-1 заканчивается как отрицательная 1.

В выражении:

s1 < s2-1

типы unsigned long не повышаются, поскольку они имеют более высокий «ранг», чем int / unsigned int, поэтому выражение оценивается с использованием арифметики без знака (с вычитанием из вычитания) и с помощью s2-1 подвыражение дает очень большое число, а не отрицательное 1.

Как указано в комментарии в виде символа lb, если в платформе int реализован как 16-битный тип (что разрешено - например, в MS-DOS), повышение unsigned short будет равно unsigned int вместо int, поскольку int не сможет представлять все значения unsigned short (unsigned short должно быть не менее 16 бит). В этом случае оба оператора if будут иметь значение true.

3 голосов
/ 12 сентября 2009

Принуждения C, как вы обнаруживаете, не всегда очевидны, когда вы работаете между разными типами. t2 - это u16, 1 - это int (предположительно, 32 бита), поэтому t2-1 является именно такой «операцией между различными типами» и приводит к общему приведению к int (поскольку оно «длиннее», чем u16 ...). Позже, поскольку s2 и 1 оба являются 32-битными (хотя и имеют разную подпись), общее приведение к длинному без знака. Таким образом, размеры участвующих типов помогают определить жесткость общего принуждения.

Я предлагаю избегать операций со смешанной подписью (и в идеале также смешанного размера!) (Посредством приведения или специальной литеральной записи для литералов, таких как 1, которые в противном случае будут иметь тип int и сделают вашу жизнь потенциально сложной и ваш код потенциально не переносимый; -).

0 голосов
/ 12 сентября 2009

-1 представляется как все 1 с. Поэтому при интерпретации как unsigned его значение равно 2 ^ 32-1, что явно больше 0. Я предполагаю, что первое сравнение расширяется для выполнения 32-битной арифметики со знаком (возможно, из-за того, что "1" является int).

Обратите внимание, что в printf попадет следующее, потому что сравнение теперь снова выполняется в 16-битном беззнаковом пространстве:

u32 temp = t2 - 1;
if( t1 < temp )
    printf(" t1 < t2-1\n");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...