Переполнение без знака в C - PullRequest
4 голосов
/ 09 октября 2010

Рассмотрим следующий фрагмент кода C:

#include <stdint.h>

uint32_t inc(uint16_t x) {
 return x+1;
}

При компиляции с gcc-4.4.3 с флагами -std = c99 -march = core2 -msse4.1 -O2 -pipe -Wall on aчисто система x86_64, она выдает

movzwl %di,%eax
inc    %eax
retq

Теперь в C прогнозируется переполнение без знака. Я не очень разбираюсь в сборке x86_64, но насколько я вижу, регистр аргумента 16 бит перемещается в 32 битрегистр, который увеличивается и возвращается.У меня вопрос, а что если x == UINT16_MAX.Произойдет переполнение, и стандарт диктует x + 1 == 0, верно?Однако, учитывая, что% eax является 32-битным регистром, он теперь содержит UINT16_MAX + 1, что неверно.

Это позволяет мне задать один вопрос: существует ли переносимый способ отключить переполнение без знака в C, чтобыкомпилятор может предположить, что верхние биты маленькой переменной, хранящиеся в большом регистре, всегда будут равны 0 (поэтому он не должен их очищать)?Если нет (или если решение синтаксически противно), есть ли способ сделать это хотя бы в GCC?

Большое спасибо за потраченное время.

Ответы [ 4 ]

6 голосов
/ 09 октября 2010

Нет, типы C подлежат акциям по умолчанию.Предполагая, что uint16_t имеет более низкий рейтинг конверсии, чем int, он будет повышен до int, и добавление будет выполнено как int, а затем будет возвращено в uint32_t при возврате.в конце вашего связанного вопроса, я не совсем понимаю, что вы хотите.

3 голосов
/ 09 октября 2010

Используйте стиль кодирования, который не использует посредников компилятора для вычислений, обратите внимание, что (1) будет иметь тип данных int.

uint32_t inc(uint16_t x) {
 uint16_t y = x + 1;
 return y;
}
0 голосов
/ 09 октября 2010

Что касается вашего второго вопроса, в C нет такой вещи, как переполнение для неподписанных типов, применимый термин - перенос.По определению беззнаковые типы вычисляются по модулю 2 ^ ширина.Всякий раз, когда вы применяете более широкий тип без знака к более узкому, верхние биты просто отбрасываются.Все компиляторы C должны реализовывать это следующим образом, вам не о чем беспокоиться.

По сути, неподписанные типы довольно просты, неприятные вещи возникают только для подписанных типов.

0 голосов
/ 09 октября 2010

Особенность способа, которым стандарт описывает целочисленное переполнение, состоит в том, что он позволяет компиляторам предполагать, что переполнение не может произойти. В случае, показанном там, компилятор не должен сохранять поведение переполнения, поскольку, в конце концов, диапазон возможных значений, которые может принимать x + 1 (при условии, что переполнения не существует), соответствует типу возврата.

...