Когда uint8_t ≠ без знака char?
В соответствии с C и С++, CHAR_BIT >= 8
.
Но всякий раз, когда CHAR_BIT > 8
, uint8_t
не может быть даже представлен как 8 бит.
Он должен быть больше, потому что CHAR_BIT
- минимальное количество бит для любого типа данных в системе.
В какой системе можно < <22 > быть юридически определенным как тип, отличный от unsigned char
?
(Если ответ отличается для C и С++, тогда я хотел бы знать оба.)
Ответы
Ответ 1
Если он существует, uint8_t
должен всегда иметь ту же ширину, что и unsigned char
. Однако он не должен быть одного и того же типа; это может быть отдельный расширенный целочисленный тип. Он также не должен иметь то же представление, что и unsigned char
; например, биты могут интерпретироваться в обратном порядке. Это глупый пример, но имеет смысл для int8_t
, где signed char
может быть дополнением или знаковой величиной, а int8_t
требуется, чтобы быть дополнением.
Еще одно "преимущество" использования расширенного целочисленного типа без char для uint8_t
даже в "нормальных" системах - это правила сглаживания C. Символьным типам присваивается псевдоним, что предотвращает компилятор от сильно оптимизирующих функций, которые используют указатели на указатели и указатели для других типов, если только ключевое слово restrict
не применяется. Однако даже если uint8_t
имеет тот же размер и представление, что и unsigned char
, если реализация сделала его отличным, несимвольным типом, правила псевдонимов не будут применяться к нему, и компилятор мог бы предположить, что объекты типов uint8_t
и int
, например, никогда не могут быть псевдонимом.
Ответ 2
О какой системе может быть uint8_t
юридически определен тип, отличный от unsigned char
?
Таким образом, uint8_t
может быть юридически определен только в системах, где CHAR_BIT
равно 8. Это адресная единица с ровно 8 битами значения и не заполняющими битами.
Подробно, CHAR_BIT
определяет ширину наименьших адресуемых единиц, а uint8_t
не может иметь биты заполнения; он может существовать только тогда, когда наименьшая адресуемая единица составляет ровно 8 бит. Предоставление CHAR_BIT
равно 8, uint8_t
может быть определено определением типа для любого 8-битного целого беззнакового типа, у которого нет дополнительных битов.
Вот что говорится в стандартном черновике C11 (n1570.pdf):
5.2.4.2.1 Размеры целых типов1 Значения, приведенные ниже, должны быть заменены постоянными выражениями, подходящими для использования в #if препроцессорные директивы.... Их значения, определяемые реализацией, должны быть равны или больше по величине (по абсолютной величине) к показанным, с тем же знаком.
-- number of bits for smallest object that is not a bit-field (byte)
CHAR_BIT 8
Таким образом, наименьшие объекты должны содержать точно биты CHAR_BIT.
6.5.3.4 Операторы sizeof и _Alignof
...
4 Когда sizeof применяется к операнду с типом char, без знака char или подписанный char (или его квалифицированная версия), результат 1....
Таким образом, это (некоторые из) наименьших адресуемых единиц. Очевидно, что int8_t
и uint8_t
также могут считаться наименьшими адресуемыми единицами, если они существуют.
7.20.1.1 Точные целые типы
1 Имя typedef intN_t обозначает знаковый целочисленный тип с шириной N, без битов дополнений и двухкомпонентного представления. Таким образом, int8_t обозначает такой знаковый целочисленный тип с шириной ровно 8 биты.
2 Имя typedef uintN_t обозначает целочисленный тип без знака с ширина N и без битов заполнения. Таким образом, uint24_t обозначает такой неподписанный целочисленный тип с шириной ровно 24 бита.
3 Эти типы являются необязательными. Однако, если реализация обеспечивает целочисленные типы с шириной 8, 16, 32 или 64 бита, без битов заполнения, и (для подписанных типов), которые имеют двойной набор представления, он должен определить соответствующие имена typedef.
Акцент на " Эти типы являются необязательными" - мой. Надеюсь, это было полезно:)
Ответ 3
Возможность, о которой никто не упомянул: если CHAR_BIT==8
и неквалифицированный char
не имеет знака, который он находится в некоторых ABI, тогда uint8_t
может быть typedef для char
вместо unsigned char
. Это имеет значение, по крайней мере, в той мере, в какой это влияет на выбор перегрузки (и его злой двойник, изменение имени), т.е. Если вы должны иметь как foo(char)
, так и foo(unsigned char)
в области видимости, вызов foo
с аргументом типа uint8_t
предпочитают foo(char)
на такой системе.