Переполнение в битовых полях
могу ли я доверять, что компилятор C делает по модулю 2^n каждый раз, когда я обращаюсь к битовому полю? Или есть ли компилятор / оптимизация, где код, подобный приведенному ниже, не будет распечатывать переполнение?
struct {
uint8_t foo:2;
} G;
G.foo = 3;
G.foo++;
if(G.foo == 0) {
printf("Overflown");
}
заранее спасибо, Флориан
3 ответов
Да, вы можете доверять компилятору C, чтобы сделать правильную вещь здесь, пока битовое поле объявлено с типом без знака, который у вас есть с uint8_t
. Из стандарта C99 §6.2.6.1/3:
значения, хранящиеся в беззнаковых битовых полях и объектах типа unsigned char, должны быть представлены с использованием чистой двоичной нотации.40)
из §6.7.2.1/9:
битовое поле интерпретируется как целое число со знаком или без знака тип, состоящий из указанного количества битов.104) если значение 0 или 1 хранится в битовом поле ненулевой ширины типа
_Bool
, значение битового поля должно сравниваться равным сохраненному значению.
и из §6.2.5/9 (выделено мной):
диапазон неотрицательных значений целочисленного типа со знаком является поддиапазоном соответствующего целочисленного типа без знака, и представление одного и того же значения в каждом типе является тот же.31)вычисление с использованием операндов без знака никогда не может переполняться, потому что результат, который не может быть представлен результирующим целочисленным типом без знака, уменьшается по модулю числа, которое больше наибольшего значения, которое может быть представлено результирующим типом.
Так что да, вы можете быть уверены, что любой отвечающий стандартам компилятор будет G.foo
переполнение до 0 без каких-либо других нежелательных побочных эффектов.
нет. Компилятор выделяет полю 2 бита, а увеличение 3 приводит к 100b, что при размещении в двух битах приводит к 0.
короткий ответ: да, вы можете доверять модулю 2^n.
В вашей программе,
G.foo++;
фактически эквивалентно G.foo = (unsigned int)G.foo + 1
.
unsigned int арифметика всегда дает 2^(размер unsigned int в битах) результаты. Два бита наименьшего веса затем сохраняются в G.foo
, производя ноль.