Незнакомое целочисленное смещение битового поля дает целое число со знаком
Рассмотрим следующую программу test.c
:
#include <stdio.h>
struct test {
unsigned int a:5;
};
int main () {
unsigned int i;
struct test t = {1};
for (i = 0; i < t.a << 1; i++)
printf("%u\n", i);
return 0;
}
При компиляции с gcc -Wsign-compare test.c
создается следующее предупреждение (проверено с помощью gcc 4.8.1):
test.c:9:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (i = 0; i < t.a << 1; i++)
^
clang -Wsign-compare test.c
выдает следующее (проверено с помощью clang 3.2):
test.c:9:19: warning: comparison of integers of different signs: 'unsigned int' and 'int' [-Wsign-compare]
for (i = 0; i < t.a << 1; i++)
~ ^ ~~~~~~~~
1 warning generated.
Таким образом, правый операнд, сдвинутое беззнаковое битовое поле, становится подписанным int. Это предупреждение показывает, какое значение поля бит составляет от 1 до 31. Для более высоких значений предупреждения не производится. Это странно.
Это было протестировано с битовым полем типа unsigned short
, unsigned int
и unsigned long
. Последние не показывают предупреждения о значениях полей бит между 32 и 64.
Если смещение не выполняется, предупреждение не появляется, поэтому поле бит не имеет знака, как ожидалось.
Почему бит бит размером менее 32 бит становится подписанным при сдвиге? Я предполагаю, что это не ошибка, так как это соответствует как gcc
, так и clang
. Мне нужно пропустить некоторую информацию о том, как работают битовые поля (или перемещение), но что? Как смещать значение без знака дает знаковое значение?
Ответы
Ответ 1
Целочисленные рекламные акции применяются к операндам сдвига, охватываемым в черновик проекта C99 раздел 6.5.7
Операторы побитового смены, пункт 3, который гласит (акцент мой вперед):
Целочисленные рекламные акции выполняются для каждого из операндов. [...]
а целочисленное продвижение битового поля рассматривается в разделе 6.3.1.1
Логические символы, символы и целые числа, которые гласят:
В выражении могут использоваться следующие выражения: int или unsigned int может:
и содержит следующую марку:
- Битовое поле типа _Bool, int, signed int или unsigned int.
а затем говорит:
Если int может представлять все значения исходного типа, значение преобразуется в int;, в противном случае оно преобразуется в unsigned int. Они называются целыми числами рекламные акции. 48) Все остальные типы не изменяются целыми рекламными акциями.
было разъяснено в проекте C11 стандарт:
Если int может представлять все значения исходного типа (как ограничение по ширине для битового поля), значение преобразуется в int; в противном случае он преобразуется в unsigned int. Они называются целыми рекламными акциями. 58) Все остальные типы не изменяются целыми рекламными акциями.
Итак, это ожидаемое поведение.