Проверка порядка работы машины - PullRequest
0 голосов
/ 04 сентября 2011

Вот программа, которую я использовал:

int hex = 0x23456789;
char * val = &hex;
printf("%p\n",hex);
printf("%p %p %p %p\n",*val,*(val+1),*(val+2),*(val+3));

Вот мой вывод:

0x23456789
0xffffff89 0x67 0x45 0x23

Я работаю на 64-битном процессоре с 64-битной ОС.Это показывает, что моя машина не имеет порядкового номера.Почему первый байт 0xffffff89?Почему ФФ?

Ответы [ 5 ]

5 голосов
/ 04 сентября 2011

Во-первых, вы должны использовать% x, поскольку это не указатели.

Спецификаторы% x ожидают целое число. Поскольку вы передаете значение типа 'char', являющегося типом со знаком, значение преобразуется в целое число и расширяется до знака. http://en.wikipedia.org/wiki/Sign_extension

Это, по сути, означает, что он берет самый старший бит и использует его для всех старших бит. Таким образом, 0x89 => 0b10001001, у которого старший бит равен 1, становится 0xFFFFFF89.

Правильное решение - указать параметры параметра 'length'. Вы можете получить больше информации здесь: Printf Заполнители По сути, между '%' и 'x' вы можете поместить дополнительные параметры. «чч» означает, что вы передаете значение char.

int hex = 0x23456789;
char *val = (char*)&hex;

printf("%x\n",hex);
printf("%hhx %hhx %hhx %hhx\n", val[0], val[1], val[2], val[3]);
3 голосов
/ 04 сентября 2011

char - это тип со знаком, он передается в int при передаче в качестве аргумента.Эта акция вызывает расширение знака.0x89 является отрицательным значением для char, поэтому оно увеличивается до 0xffffff89.Это не происходит для других значений, они не превышают CHAR_MAX, 127 или 0x7f на большинстве машин.Это поведение вас смущает, поскольку вы используете неправильный спецификатор формата.

2 голосов
/ 04 сентября 2011

% p просит printf отформатировать его как адрес , вы фактически передаете значение (* val)

На 64-битном компьютере указатели адреса являются 64-битными, поэтому printf добавляет ffff для заполнения полей

1 голос
/ 05 сентября 2011

Я проверяю порядок байтов с условием ((char)((int)511) == (char)255).True означает маленький, false означает большой.

Я проверил это на нескольких отдельных системах, как малых, так и больших, используя gcc с отключенной оптимизацией и макс.В каждом тесте, который я проводил, я получал правильные результаты.

Вы могли бы поместить это условие в if вашего приложения до того, как оно должно будет выполнять операции с критическим порядком байтов.Если вы хотите только гарантировать, что вы используете правильный порядок байтов для всего вашего приложения, вы можете вместо этого использовать статический метод утверждения, такой как:

extern char ASSERTION__LITTLE_ENDIAN[((char)((int)511) == (char)255)?1:-1];

Эта строка в глобальной области действия создаст компиляциюошибка, если система не имеет порядка байтов и будет отказываться от компиляции.Если ошибки не было, она прекрасно компилируется, как если бы эта строка не существовала.Я нахожу, что сообщение об ошибке довольно наглядно:

error: size of array 'ASSERTION__LITTLE_ENDIAN' is negative

Теперь, если вы не знаете, как ваш компилятор оптимизирует фактическую проверку, как я, вы можете сделать следующее:

int endian;
{
    int i = 255;
    char * c = &i;
    endian = (c[0] == (char)255);
}
if(endian) // if endian is little

Что хорошо сжимается в этот макрос:

#define isLittleEndian(e) int e; { int i = 255; char * c = &i; e = (c[0] == (char)255); }
isLittleEndian(endian);
if(endian) // if endian is little

Или, если вы используете GCC, вы можете сойти с:

#define isLittleEndian ({int i = 255; char * c = &i; (c[0] == (char)255);})
if(isLittleEndian) // if endian is little
1 голос
/ 04 сентября 2011

Как сказал @Martin Beckett, %p просит printf напечатать указатель, что эквивалентно %#x или %#lx (точный формат зависит от вашей ОС).

Это означает, что printf ожидает int или long (опять же, зависит от ОС), но вы предоставляете ему только char, поэтому значение преобразуется в соответствующий тип.

Когда вы преобразуете меньшее число со знаком в большее число со знаком, вы должны сделать что-то под названием расширение знака , чтобы сохранить значение. В случае 0x89 это происходит потому, что бит знака установлен, поэтому старшие байты равны 0xff и печатаются, потому что они значимы.

В случае 0x67, 0x45, 0x23 расширение знака не происходит, поскольку бит знака не установлен, и поэтому старшие байты равны 0 и, следовательно, не печатаются.

...