3 main(int argc, char **argv)
4 {
5 union {
6 short s;
7 char c[sizeof(short)];
8 } un;
9 un.s = 0x0102;
10 printf("%s: ", CPU_VENDOR_OS);
11 if (sizeof(short) == 2) {
12 if (un.c[0] == 1 && un.c[1] == 2)
13 printf("big-endian\n");
14 else if (un.c[0] == 2 && un.c[1] == 1)
15 printf("little-endian\n");
16 else
17 printf("unknown\n");
18 } else
19 printf('sizeof(short) = %d\n", sizeof(short));
20 exit(0);
21 }
Мы помещаем двухбайтовое значение
0x0102
в переменную типа
short
(короткое целое) и проверяем значения двух байтов этой переменной:
с[0]
(адрес А на рис. 3.4) и
c[1]
(адрес А + 1 на рис. 3.4), чтобы определить порядок байтов.
Константа
CPU_VENDOR_OS
определяется программой GNU (аббревиатура «GNU» раскрывается рекурсивно — GNU's Not Unix)
autoconf
в процессе конфигурации, необходимой для выполнения программ из этой книги. В этой константе хранится тип центрального процессора, а также сведения о производителе и реализации операционной системы. Ниже представлены некоторые примеры вывода этой программы при запуске ее в различных системах (см. рис. 1.7).
freebsd4 %
byteorder
i386-unknown-freebsd4.8: little-endian
macosx %
byteorder
powerpc-apple-darwin6.6: big-endian
freebsd5 %
byteorder
sparc64-unknown-freebsd5.1: big-endian
aix %
byteorder
powerpc-ibm-aix5.1.0.0: big-endian
hpux %
byteorder
hppa1.1-hp-ux11 11: big-endian
linux %
byteorder
i586-pc-linux-gnu: little-endian
solaris %
byteorder
sparc-sun-solaris2.9: big-endian
Все, что было сказано об определении порядка байтов 16-разрядного целого числа, конечно, справедливо и в отношении 32-разрядного целого.
Существуют системы, в которых возможен переход от прямого к обратному порядку байтов либо при перезапуске системы (MIPS 2000), либо в любой момент выполнения программы (Intel i860).
Разработчикам сетевых приложений приходится обрабатывать различия в определении порядка байтов, поскольку в сетевых протоколах используется
Теоретически реализация Unix могла бы хранить поля структуры адреса сокета в порядке байтов узла, а затем выполнять необходимые преобразования при перемещении полей в заголовки протоколов и обратно, позволяя нам не беспокоиться об этом. Но исторически и с точки зрения POSIX определяется, что для некоторых полей в структуре адреса сокета порядок байтов всегда должен быть сетевым. Поэтому наша задача — выполнить преобразование из порядка байтов узла в сетевой порядок и обратно. Для этого мы используем следующие четыре функции:
#include
uint16_t htons(uint16_t
uint32_t htonl(uint32_t
uint16_t ntohs(uint16_t
uint32_t ntohl(uint32_t
В названиях этих функций
h
обозначает
n
обозначает
s
— тип
l
— тип
s
как 16-разрядное значение (например, номер порта TCP или UDP), а
l
— как 32-разрядное значение (например, адрес IPv4). В самом деле, в 64-разрядной системе Digital Alpha длинное целое занимает 64 разряда, а функции
htonl
и
ntohl
оперируют 32-разрядными значениями (несмотря на то, что используют тип
long
).