Когда uint8_t ≠ беззнаковый символ?

Согласно C и C ++, CHAR_BIT >= 8.
Но всякий раз, когда CHAR_BIT > 8, uint8_t не может быть даже представлен как 8 бит.
Он должен быть больше, потому что CHAR_BIT - это минимальное количество бит для любого типа данных в системе.

В какой системе uint8_t может быть юридически определен тип, отличный от unsigned char?

(Если ответ на C и C ++ разный, я хотел бы знать оба.)


person user541686    schedule 22.04.2013    source источник
comment
Интересно, законно ли иметь char только с 7 реальными битами и 1 битом заполнения.   -  person Mysticial    schedule 22.04.2013
comment
@Mysticial: Нет, я думаю, что все chars должны иметь все биты представления, участвующие в определении их значения.   -  person user541686    schedule 22.04.2013
comment
Или, может быть, 16-битный uint8_t, где 8 - действительное значение, а 8 - заполнение. Я бы выстрелил в любого, кто создал такую ​​среду. :)   -  person Mysticial    schedule 22.04.2013
comment
В стандарте C ++ это указано как необязательное. typedef signed integer type int8_t; // optional   -  person Rapptz    schedule 22.04.2013
comment
@Mysticial: Не уверен, что это разрешено, потому что ширина должна быть ровно 8 бит. :П   -  person user541686    schedule 22.04.2013
comment
@Mysticial: [u] int * _t требуется по стандарту, чтобы не иметь битов заполнения и быть дополнением до двух, если подписано.   -  person R.. GitHub STOP HELPING ICE    schedule 22.04.2013
comment
@Mysticial: Разве ты не потерял бы дальность, если бы это случилось? Это означает, что вам нужны все 8 бит для представления некоторого char.   -  person    schedule 22.04.2013
comment
@Mysticial: такие среды действительно существуют (архитектуры DSP обычно не могут адресовать что-либо меньшее, чем слово); в этом случае uint8_t вообще не должно существовать.   -  person Mike Seymour    schedule 25.04.2013
comment
Возможный дубликат uint8_t vs unsigned char   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 13.11.2016


Ответы (3)


Если он существует, uint8_t всегда должен иметь ту же ширину, что и unsigned char. Однако это не обязательно должно быть одного и того же типа; это может быть отдельный расширенный целочисленный тип. Он также не обязательно должен иметь то же представление, что и unsigned char; например, биты можно интерпретировать в обратном порядке. Это глупый пример, но он имеет больше смысла для int8_t, где signed char может быть дополнением до единиц или величиной знака, в то время как int8_t должен быть дополнением до двух.

Еще одно «преимущество» использования расширенного целочисленного типа без символов для uint8_t даже в «обычных» системах - это правила псевдонима языка Си. Типам символов разрешено использовать псевдонимы для чего угодно, что не позволяет компилятору сильно оптимизировать функции, которые используют как символьные указатели, так и указатели на другие типы, если ключевое слово restrict не было применено правильно. Однако даже если uint8_t имеет тот же размер и представление, что и unsigned char, если реализация сделала его отдельным, несимвольным типом, правила псевдонима к нему не применялись бы, и компилятор мог предположить, что объекты типов uint8_t и int, например, никогда не может псевдоним.

person R.. GitHub STOP HELPING ICE    schedule 22.04.2013
comment
Если я считаю, что фрагмент черновика стандарта, опубликованный в другом ответе, uint8_t должен быть определен как typedef. - person Mark Ransom; 22.04.2013
comment
typedef __uint8_t uint8_t; - это typedef. - person R.. GitHub STOP HELPING ICE; 22.04.2013
comment
В интересах юмора, возможно, реализация может решить быть совместимой с ее соглашениями об именах и, в отличие от long long, может ввести short short. Следовательно, _3 _... - person autistic; 22.04.2013
comment
В 2003 ± 2 (не собираюсь сейчас копать это в почтовых архивах) команда GCC рассматривала возможность создания [u]int8_t специальных расширенных целочисленных типов именно так, чтобы их можно было оптимизировать более агрессивно ... но в конечном итоге отвергла эту идею на том основании, что что программисты, скорее всего, будут ожидать от них тех же специальных свойств псевдонима, что и char. (Это было примерно в то же время, когда разработчики ядра кричали нас за то, что мы проводим анализ псевдонимов на основе типов вообще, так что мы все были немного пугливы.) - person zwol; 25.04.2013
comment
@Zack: Спасибо за интересную историческую заметку. Было бы неплохо, если бы gcc по-прежнему предоставлял эти типы, но не использовал их по умолчанию, чтобы макрос проверки функций или аналогичный мог переключаться на них, обеспечивая более агрессивную оптимизацию. - person R.. GitHub STOP HELPING ICE; 25.04.2013
comment
@Zack интересно, ну, эта проблема возникла в вопросе сегодня, и я не вижу переносимого обходного пути, что, к сожалению, . +1 кстати. - person Shafik Yaghmour; 11.10.2014
comment
@ShafikYaghmour: Хороший вопрос. Однако тривиальный обходной путь состоит в том, чтобы использовать ключевое слово restrict или скопировать указатель на локальную переменную, адрес которой никогда не используется, чтобы компилятору не нужно было беспокоиться о том, могут ли объекты uint8_t использовать его псевдоним. - person R.. GitHub STOP HELPING ICE; 11.10.2014
comment
@R .. спасибо за предложение, OP опубликовал дополнительный вопрос и заявил, что restrict не работает в gcc для них, но другое предложение работает. - person Shafik Yaghmour; 11.10.2014
comment
Разделение uint8_t из символьных типов фактически обсуждалось на bugzilla GCC: см. ‹gcc.gnu .org / bugzilla / show_bug.cgi? id = 66110 ›. - person user3840170; 04.01.2021

На каком типе системы 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, unsigned char или signed 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.

Я делаю акцент на «Эти типы необязательны». Я надеюсь, что это было полезно :)

person autistic    schedule 22.04.2013
comment
Так в чем же цель uint8_t, если он никогда не отличается от unsigned char? - person user541686; 22.04.2013
comment
@Mehrdad Я думаю, что в случае, когда вам действительно нужен int8, он вообще не будет компилироваться, когда CHAR_BIT > 8, поскольку int8_t даже не существовало бы. Тогда как при использовании char и CHAR_BIT > 8 вы можете получить полуразрушенную сборку. - person Mysticial; 22.04.2013
comment
@Mysticial: Странно, не могли бы вы уже просто сказать #if CHAR_BIT > 8... #error ZOMG... #endif, если ваша программа не должна работать в этих системах? - person user541686; 22.04.2013
comment
Он отличается от unsigned char. unsigned char гарантированно существует, но гарантированно будет 8 бит только при CHAR_BIT == 8. uint8_t не гарантируется, что существует, но гарантированно будет иметь 8 бит, когда это произойдет. - person autistic; 22.04.2013
comment
Есть тонкая разница между char и int8_t, помимо ширины. char может использовать представление с дополнением до единиц, дополнением до двух или знаком и величиной, где int8_t требуется для использования представления с дополнением до двух. - person autistic; 22.04.2013
comment
Я всегда думал, что смысл всех типов определенного размера в том, чтобы, если происходило что-то странное, вещи либо продолжали работать, либо сразу ломались, и вам об этом говорили. Они также намного более читабельны, когда вы не работаете с chars. - person ssube; 22.04.2013
comment
Также было бы хорошо сказать, если char гарантированно будет иметь CHAR_BIT бит, и процитировать стандарт для этого. - person Ciro Santilli 新疆再教育营六四事件ۍ 19.11.2018
comment
Эй, если вы решите удалить свои ответы, пингуйте меня, чтобы я мог перепостить их и получить репутацию, ха-ха. Но сейчас у меня достаточно репутации для рынка труда, я просто делаю это, чтобы спасти мир. Что я действительно хочу сейчас, так это зарабатывать деньги. - person Ciro Santilli 新疆再教育营六四事件ۍ 19.11.2018
comment
@autistic Я думал, что невозможно отказаться от CC BY-SA своих ответов. Но тебе следует расслабиться, я просто шучу. - person Ciro Santilli 新疆再教育营六四事件ۍ 20.11.2018
comment
Хорошо, я понимаю, что ты имеешь в виду. - person Ciro Santilli 新疆再教育营六四事件ۍ 21.11.2018
comment
@autistic char может быть unsigned, int8_t подписано. - person 12431234123412341234123; 24.12.2020
comment
@ 12431234123412341234123 правда. Я не могу отредактировать это в комментарии, но дайте знать, что я хотел упомянуть возможность того, что char является беззнаковым типом. - person autistic; 06.05.2021

Возможность, о которой пока никто не упоминал: если CHAR_BIT==8 и unqualified char беззнаковый, как в некоторых ABI, тогда uint8_t может быть typedef для char вместо unsigned char. Это имеет значение, по крайней мере, постольку, поскольку это влияет на выбор перегрузки (и его злого близнеца, искажение имени), то есть если бы у вас были и foo(char), и foo(unsigned char) в области видимости, вызов foo с аргументом типа uint8_t предпочел бы foo(char) в такой системе.

person zwol    schedule 24.04.2013
comment
Однако это не обязательно должно быть одного и того же типа; это может быть отдельный расширенный целочисленный тип. частично покрывает это, хотя это правда, что это легко может быть упущено из виду. - person Luc Danton; 25.04.2013
comment
@LucDanton char не является расширенным целочисленным типом. - person zwol; 25.04.2013
comment
это не обязательно того же типа, это соответствующая часть. Остальное я взял за пример. - person Luc Danton; 25.04.2013