Рассмотрим следующую программу 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
. Мне нужно пропустить некоторую информацию о том, как работают битовые поля (или перемещение), но что? Как смещать значение без знака дает знаковое значение?