Безопасно ли обнаруживать endianess с помощью соединения?
Другими словами, согласно стандарту C , этот код безопасен? (Предположим, что uint8_t
- один байт)
void detectEndianness(void){
union {
uint16_t w;
uint8_t b;
} a;
a.w = 0x00FFU;
if (a.b == 0xFFU) {
puts("Little endian.");
}
else if (a.b == 0U) {
puts("Big endian.");
}
else {
puts("Qaru endian.");
}
}
Что, если я изменю это на это? Обратите внимание на третий случай if
, о котором я знаю.
a.w = 1U;
if (a.b == 1U) { puts("Little endian."); }
else if (a.b == 0U) { puts ("Big endian."); }
else if (a.b == 0x80U) { /* Special potential */ }
else { puts("Qaru endian."); }
Ответы
Ответ 1
Цитата из n1570:
6.5.2.3 Элементы структуры и объединения - p3
Постфиксное выражение, за которым следует. оператор и идентификатор обозначает элемент структуры или объект объединения. Значение таково: именованного члена, и является значением lvalue, если первое выражение является именующий.
6.2.6 Представления типов /1 Общие - p7
Когда значение хранится в члене объекта типа объединения, байты представления объекта, которые не соответствуют этому член, но соответствуют другим членам, принимают неопределенные значения.
Это разрешено. И ваш прецедент можно считать одной из намеченных целей, если примечание 95 принимается во внимание (несмотря на то, что оно только информативное):
Если элемент, используемый для чтения содержимого объекта объединения, не является тот же самый, что и последний элемент, используемый для хранения значения в объекте, Соответствующая часть объектного представления значения равна реинтерпретируется как представление объекта в новом типе, как описано в 6.2.6 (процесс, иногда называемый "пингом типа" ). Это может быть представление ловушки.
Теперь, поскольку семейство типов uintN_t определено, что не имеет битов заполнения
7.20.1.1 Целые числа точной ширины - p2
Имя typedef uintN_t обозначает целочисленный тип без знака с ширина N и без битов заполнения. Таким образом, uint24_t обозначает такой неподписанный целочисленный тип с шириной ровно 24 бита.
Все их битовые представления являются допустимыми значениями, не допускаются представления ловушек. Поэтому мы должны заключить, что он действительно проверит для endianess uint16_t
.
Ответ 2
Стандарт (доступен в связанном онлайн-проекте) в footnote указывает, что ему разрешен доступ к другому члену того же союза чем ранее записанный член:
95) Если элемент, используемый для чтения содержимого объекта объединения, не является то же, что и последний элемент, используемый для хранения значения в объекте, Соответствующая часть объектного представления значения равна реинтерпретируется как представление объекта в новом типе, как описано в 6.2.6 (процесс, иногда называемый "type punning" ). Это может быть представление ловушки.
Но в сноске также упоминается возможное ловушечное представление, и единственным типом данных, который гарантируется стандартом, который должен быть безопасным относительно представлений о ловушках, является unsigned char
. Доступ к представлениям ловушек может быть undefined; и хотя я не думаю, что unit_32
может отображать ловушку на вашей платформе, на самом деле реализация зависит от того, является ли доступ к этому члену UB или нет.
Ответ 3
Нет требования, чтобы порядок бит в байте соответствовал порядку соответствующих бит в большем типе. Соответствующая реализация, которая определяет uint32_t
и имеет 8-разрядный unsigned char
, может, например, хранить верхние 16 бит uint32_t, используя четыре бита из каждого байта, и хранить нижние 16 бит, используя оставшиеся четыре бита каждого байт. С точки зрения Стандарта, любой из 32! перестановки бит будут одинаково приемлемыми.
Было сказано, что любая реализация, которая не является намеренно тупой и предназначена для работы на обычной платформе, будет использовать один из двух порядков [обработка байтов как групп из 8 последовательных бит в порядке 0123 или 3210] и тот, который не использует одно из указанных выше, и нацелен на любую платформу, которая не является полностью неясной, будет использовать 2301 или 1032. Стандарт не запрещает другие заказы, но неспособность их разместить вряд ли вызовет какие-либо проблемы, кроме при использовании тупо надуманных реализаций.