+133
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
Говнокод из http://stackoverflow.com/questions/2100331/c-macro-definition-to-determine-big-endian-or-little-endian-machine
Мало того, что писать в один тип из юниона и потом читать из другого это UB, так еще компилятор (в случае GCC) из
int main(void)
{return O32_HOST_ORDER == O32_LITTLE_ENDIAN;}
нагенерирует код
main:
xor eax, eax
cmp DWORD PTR o32_host_order[rip], 50462976
sete al
ret
o32_host_order:
.byte 0
.byte 1
.byte 2
.byte 3
т.е. всякий раз, когда надо узнать endianess, мы лезем в константную статическую переменную и сравниваем ее с константой
Запостил:
j123123,
08 Апреля 2014
ЩИТО? Можно цитату из стандарта?
Page 38, 6.2.6.1
Change paragraph 7 to:
When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.
Так мы по этим unspecified values и хотим понять, какая же endianness. Это не то же самое, что UB.
А если у нас будут еще и структуры в юнионе, в структурах может быть разный alignment на разных компиляторах (и даже разных таргетах одного компилятора) и соответственно там могут быть дырки, всякие хитрые перекрытия полей структур, стандарт это поведение никак не регламентирует
... с точки зрения абстрактного ISO стандарта. а с точки зрения конкретной реализации (железо + OS + этц) это вполне определенная вещь. потому что бы иначе ни одна ось, писаная на С не забутилась бы.
погугли "sysv abi x86-64" pdf'ку.
А так бы ведь пересели с асма на что-то по типу LLVM IR. Портабельно же.
Кросскомпиляцию можно забыть?
Ну тесты соберешь кросскомпилером и на таргете прогонишь. Если там найдется чем их запустить :)
Вообще это какая-то мутная и неоднозначная фразочка.
Если у нас есть юнион типа
Черт знает что
в be.bytes[0] или be.bytes[5] в зависимости от индусности машины будет неизвестное значение после присвоения be.value = 0;
Что намекает нам ещё раз вопреки практике о бесполезности присвоений и чтений в\из разных членов, тк нет гарантии сохранения нетронутого байта в первозданном виде (в том виде, что до присвоения be.value = 0;).
Прозаично, но сишники обожают юзать юнионы для разруливания strict aliasing и записи по частям.
Возможно, вы имели в виду be.bytes[3]?
В некоторых случаях этот самый юнион используется как раз для выравнивания, чтобы не использовать гцц-шные атрибуты и прагма пак (их в стандарте точно нет) https://github.com/radare/radare2/blob/086fc30e3bee81cee3eb7678757443beda46d42a/shlr/sdb/src/cdb_make.c#L13
Ок, будем знать :)
[quote]The behavior of type punning with union changed from C89 to C99. The behavior in C99 is the same as C11.
As Wug noted in his answer, type punning is allowed in C99 / C11. An unspecified value that could be a trap is read when the union members are of different size.[/quote]
Другие отвечают что примечание не имеет юридической силы.
http://gcc.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A {%22labels%22%3Atrue%2C%22directives%22% 3Atrue%2C%22commentOnly%22%3Atrue%2C%22i ntel%22%3Atrue}%2C%22compilers%22%3A[{%22sourcez%22%3A%22MQSwdgxgNgrgJgUwAQB4 DOAXO4MDoAWAfAFDE5IhoD6UIGGUCVCY2AhmABQB uA9iHACUSAN7EkEpDDAheYUeMkSAkNLQgA5mARwk EfGwBOSAEYBPDAjQBtACwBdANyKlEmDgDMAJioYk 3NlgEZyUAXyRGJABeUQAGAA9YgEYAGiQE2K80jI9 sxNtQ5xckQwQMGEN5DNtYj0zk6JjGXACg51DScko qE01mVhAOHn4hBSVpWXkxVyRVMHUtHT0DY3NLGwc QmalPHz9WmGDi8JNkGJFqvNqrrPTEpMLSJVLyyrv YmrqvBqiY05bAod2kAAA%22%2C%22compiler%22 %3A%22%2Fusr%2Fbin%2Fclang%2B%2B%22%2C%2 2options%22%3A%22-O3%20%22}]}
Должно помочь.
У меня иррациональная неприязнь к сокращалкам ссылок, даже если они, как например здесь, уместны.
С армами и gcc вообще интересная ситуация
https://en.wikipedia.org/wiki/Endianness#Bi-endian_hardware
Some architectures (including ARM versions 3 and above, PowerPC, Alpha, SPARC V9, MIPS, PA-RISC, SuperH SH-4 and IA-64) feature a setting which allows for switchable endianness in data segments, code segments or both. This feature can improve performance or simplify the logic of networking devices and software. The word bi-endian, when said of hardware, denotes the capability of the machine to compute or pass data in either endian format.
Ну и в самом гцц есть опции для выставления режима http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
-mlittle-endian
Generate code for a processor running in little-endian mode. This is the default for all standard configurations.
-mbig-endian
Generate code for a processor running in big-endian mode; the default is to compile code for a little-endian processor.
-mwords-little-endian
This option only applies when generating code for big-endian processors. Generate code for a little-endian word order but a big-endian byte order. That is, a byte order of the form ‘32107654’. Note: this option should only be used if you require compatibility with code for big-endian ARM processors generated by versions of the compiler prior to 2.8. This option is now deprecated.
И мальчиков и девочек любит? На ходу что-ли менять умеет?
A2.7 Endian support
FreeBSD clang version 3.3 вообще отказался это собирать, сказав:
constexpr function never produces a constant expression.
note: read of member 'value' of union with active member 'bytes' is not allowed in a constant expression
Компиляторы, которые есть в списке gcc.godbolt.org, все-таки собрали это.
Несмотря на наличие constexpr, ICC все равно нагенерировал сравнение: http://goo.gl/aGj8zF
С GCC под ARM похожая история: http://goo.gl/e9ePxW Я не очень умею читать ассемблер на ARM, но вроде все выходит так:
Сперва по кусочкам (!) {0x01, 0x02, 0x03, 0x04} загружается в регистр r3 (см. инструкции BFI, Bit Field Insert), затем 0x4030201 грузится за два захода в r4 через пару mov и movt (ARM, походу, иначе не умеет), и потом они сравниваются.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cjagdjbf.html
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cihcdbca.html
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cjagchif.html
Ты не поверишь, но он не обязан генерировать константу.
ICC: constant value is not known
GCC под ARM тоже сломался:
in constexpr expansion of ‘is_little_endian()’
error: accessing ‘lol_t::value’ member instead of initialized ‘lol_t::bytes’ member in constant expression
Походу, компиляторы проверяют constexpr на ошибки только при раскрытии.
Edit: Только шланг молодец, сразу нашел подвох.
Но не факт конечно что компиляторы заморачиваются с оптимизацией каста через юнион.