GCC меняет знак всего выражения

#c #gcc #c99 #gcc4.7

Вопрос:

У меня есть следующий код:

 unsigned int m_font_timer = 0;

int Getsum(int p_top_left_x)
{
    int l_sum = (((p_top_left_x   (m_font_timer >> 2)) amp; 0x7) - 4 ) >> 2;
    
    if (l_sum < 0) l_sum = -l_sum;
    return l_sum;
}
 

Если я явно не приведу m_font_timer к (int со знаком), эта часть выражения станет неподписанной:

 ((p_top_left_x   (m_font_timer >> 2)) amp; 0x7) - 4 );
 

Даже несмотря на то, что есть «-4» и p_top_left_x подписан.

Это происходит в кросс-компиляторе для SH4 с использованием gcc 4.7.3 (я программирую для старой системы, которая этого требует). Я не ожидал, что эта часть превратится в неподписанную. У меня есть этот код, работающий на двух других платформах, также с GCC (более высокой версией, чем эта) и одной с MSCV, и все они сохраняют вышеупомянутое выражение как подписанное.

Я мало что знаю о компиляторах, это неопределенное поведение? Есть ли какой-нибудь способ, которым компилятор предупредил бы меня об этом? У меня есть-Wall-Wformat=0-Wextra-Wsign-сравнение, но в этой функции не появляется никаких предупреждений.

Спасибо!

Комментарии:

1. это четко определенное поведение. - 4 это не отрицательное число, которое вы вычитаете только 4 из числа без знака. Поскольку выражение без знака в правой части назначения не больше, чем INT_MAX, l_sum не является отрицательным

2. Имейте в виду,что сдвиг вправо с подписью определяется реализацией.

3. Спасибо за ответ! Не будет ли l_sum отрицательным, когда (p_top_left_x (m_font_timer >>> 2)) amp; 0x7) приведет к 0? Тогда это было бы ((0 -4) >>> 2) Я просто в замешательстве, как это выражение перед последним «>>>>>>> 2» может выводить подписанный или подписанный результат в зависимости от компилятора и по-прежнему определяться

4. подписано >>2 , определена реализация , поэтому каждая реализация может реализовать ее по-своему

Ответ №1:

Преобразование типов работает по рангу и знаку: если типы имеют разный ранг — как в int и char, более низкий ранг (char) будет преобразован в более высокий ранг (int).

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

Вот несколько мест, которые подробно объясняют:

обычное арифметическое преобразование

другой источник

Комментарии:

1. Спасибо за ответ, очень признателен! Таким образом, в основном m_font_timer превращает все выражение в без знака перед последним >>>2, верно? Но разве это не должно произойти для других 2 платформ, где я использую более новую версию GCC?

2. Немного сложно попытаться рассказать, что происходит на других платформах, но в двух других случаях поведение отличается. Ожидается, что преобразование в unsigned приведет к ожидаемому результату и на моем компьютере.