Незнакомое целочисленное смещение битового поля дает целое число со знаком

Рассмотрим следующую программу 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) Все остальные типы не изменяются целыми рекламными акциями.

Итак, это ожидаемое поведение.