unsigned становится подписанным в сравнениях if-операторов? - PullRequest
8 голосов
/ 17 ноября 2010

Я искал этот сайт для ответа и нашел много ответов на сравнение без знака / со знаком, но эта проблема в том, что сравниваются только параметры без знака, но все равно это забавно.

Проблема со следующим кодом заключается в том, что первое if -статирование не происходит («привет»), как второе («мир»). Это я интерпретировал как вычисление, которое выполняется внутри if -статации, генерирует отрицательное число, но точно такое же вычисление, выполненное с результатом, сохраненным в переменных, не выполняется (даже если результат сохраняется в переменной со знаком).

Используется компилятор gcc 4.4.

unsigned short u16_varHigh;  
unsigned short u16_varLow;  
unsigned short u16_Res1;  
signed short   s16_Res1;  

u16_varHigh = 0xFFFF;  
u16_varLow = 10;

u16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected  
s16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected

// Does not enter  
if( (u16_varLow - u16_varHigh) > (unsigned short)5 )  
{  
 printf( "hello" );  
}

// Does enter  
if( (unsigned short)(u16_varLow - u16_varHigh) > 5 )  
{  
 printf( "world" );  
}

Может кто-нибудь объяснить это для меня и, возможно, придумать решение для исправления, чтобы первое if заявление также работало?

Ответы [ 4 ]

4 голосов
/ 17 ноября 2010

В выражении:

if( (u16_varLow - u16_varHigh) > (unsigned short)5 )  

(u16_varLow - u16_varHigh) будет повышен до int и оценен до -65525. Решением вашей проблемы является приведение к типу без знака, как вы это делаете в коде «Вводит».

Причина, по которой s16_Res1 = u16_varLow - u16_varHigh; приводит к 11, заключается в том, что результат вычитания -65525 не соответствует короткому.

2 голосов
/ 18 ноября 2010

В «обычных арифметических преобразованиях» типы, меньшие int, переводятся в int или unsigned int, прежде чем они используются в большинстве выражений.Правило состоит в том, что если int может представлять все значения меньшего типа, то оно повышается до int;в противном случае он повышается до unsigned int.Это часто считается чем-то вроде бородавки, потому что во многих случаях это приводит к повышению значений unsigned char и unsigned short до int.

Это именно то, что вы видите - u16_varLow иu16_varHigh и (unsigned short)5 переводятся в int до вычитания и сравнения, что затем происходит с использованием int.Если вы хотите быть уверены, что выражение будет использовать арифметику без знака, вы должны сделать это в unsigned int, , а не unsigned short:

if( ((unsigned)u16_varLow - (unsigned)u16_varHigh) > 5U )
2 голосов
/ 17 ноября 2010

В других ответах мы видели, что

u16_varLow - u16_varHigh

для вас (с 16-битным short и 32-битным int) эквивалентно

(int)u16_varLow - (int)u16_varHigh

и, следовательно, его результатом является значение int -65525. Таким образом, присвоение

s16_Res1 = u16_varLow - u16_varHigh; 

эквивалентно

s16_Res1 = -65525;

который в вашем случае 16 бит short дает "неопределенное поведение". Вам просто не повезло, что ваш компилятор решает назначить 11 вместо этого. (Не повезло, потому что я думаю, что лучше потерпеть неудачу рано.)

В отличие от этого

u16_Res1 = -65525; 

является действительным присваиванием, поскольку u16_Res1 относится к типу без знака, а арифметика типов без знака по модулю соответствует степени двойки.

1 голос
/ 17 ноября 2010

Первый, if( (u16_varLow - u16_varHigh) > (unsigned short)5 ) никогда не пройдет, так как (u16_varLow - u16_varHigh) возвращает отрицательное число, потому что оно рассматривается как целое число.Второй бросает тот же отрицательный номер в беззнаковый короткий, поэтому он проходит.

Примечание - вы знаете, что все это зависит от платформы, верно?Размер short, int и т. Д. Зависит от конкретной платформы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...