Little против Big Endianess: как интерпретировать тест - PullRequest
9 голосов
/ 02 апреля 2012

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

Это то, что я нашел в Интернете.Что означает * (char *) & x и как оно равняется единице, доказывая, что машина имеет формат Little-Endian?

int x = 1;
if (*(char *)&x == 1) {
    printf("Little-Endian\n");
} else {
    printf("Big-Endian\n");
}

Ответы [ 6 ]

14 голосов
/ 02 апреля 2012

Если мы разбиваемся на разные части:

  1. &x: получает адрес места, где находится переменная x, то есть &x является указателем на x.Тип: int *.

  2. (char *)&x: он принимает адрес x (который является int *) и преобразует его в char *.

  3. *(char *)&x: это разыменовывает char *, на который указывает &x, т.е. получает значения, хранящиеся в x.

Сейчасесли мы вернемся к x и как данные хранятся.На большинстве машин x составляет четыре байта.Хранение 1 в x устанавливает младший значащий бит на 1, а остальное на 0.На машине с прямым порядком байтов это сохраняется в памяти как 0x01 0x00 0x00 0x00, в то время как на машине с прямым порядком байтов это сохраняется как 0x00 0x00 0x00 0x01.

Что выражение делает, получает первый из этих байтов и проверяет,это 1 или нет.

4 голосов
/ 02 апреля 2012

Вот как будет выглядеть память, если принять целое число 32b:

Little-endian
0x01000000 = 00000001000...00

Big-endian
0x00000001 = 0......01

Разыменование char * дает вам один байт. Ваш тест извлекает первый байт в этой ячейке памяти, интерпретируя адрес как char *, а затем разыменовывая его.

1 голос
/ 02 апреля 2012
int x;

x - это переменная, которая может содержать 32-битное значение.

int x = 1;

Данное оборудование может хранить значение 1 как значение 32-bit в одном из следующих форматов.

Little Endian
0x100    0x101    0x102    0x103
00000001 00000000 00000000 00000000 

(or) 

Big Endian
0x100    0x101    0x102    0x103
00000000 00000000 00000000 00000001

Теперь давайте попробуем разбить выражение:

&x 

Получить адрес переменной x.Скажем, адрес x это 0x100.

(char *)&x 

&x - адрес целочисленной переменной.(char *)&x преобразует адрес 0x100 из (int *) в (char *).

*(char *)&x 

отменяет ссылку на значение, хранящееся в (char *), которое является ничем иным, как первым байтом (слева направо) в 4-байтовом (32-разрядное целое число x).

(*(char *)&x == 1)

Если первый байт слева направо хранит значение 00000001, то он имеет порядок байтов.Если 4-й байт слева направо хранит значение 00000001, то это старшее число.

1 голос
/ 02 апреля 2012

Разбивка *(char *)&x:

&x - это адрес целого числа x

(char *) приводит к тому, что адрес целого числа x обрабатывается как адрес символа (он же байт))

* ссылается на значение байта

0 голосов
/ 07 сентября 2014

Если 4-байтовое целое число без знака с прямым порядком байтов выглядит как 0xAABBCCDD, что равно 2864434397, то это же 4-байтовое целое число без знака выглядит как 0xDDCCBBAA на процессоре с прямым порядком байтов, который также равен 2864434397.

Если двухбайтовое короткое число без байтов с прямым порядком байтов выглядит как 0xAABB, равное 43707, то такое же короткое беззнаковое 2-байтовое число выглядит как 0xBBAA на процессоре младшего байта, который также равен 43707.

Вот несколько удобных функций #define, позволяющих поменять байты с младшего к старшему и наоборот ->

// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))

// can be used for int or unsigned int or float (4-byte types)
#define BYTESWAP32(n) ((BYTESWAP16((n&0xFFFF0000)>>16))|((BYTESWAP16(n&0x0000FFFF))<<16))

// can be used for unsigned long long or double (8-byte types)
#define BYTESWAP64(n) ((BYTESWAP32((n&0xFFFFFFFF00000000)>>32))|((BYTESWAP32(n&0x00000000FFFFFFFF))<<32))
0 голосов
/ 05 апреля 2013

Да, это отвечает на вопрос. Вот более общий ответ:

#include <iostream>
#include <cstdlib>  
#include <cmath>

using namespace std;

int main()
{
cout<<"sizeof(char) = "<<sizeof(char)<<endl;
cout<<"sizeof(unsigned int) = "<<sizeof(unsigned int)<<endl;
//NOTE: Windows, Mac OS, and Linux and Tru64 Unix are Little Endian architectures
//Little Endian means the memory value increases as the digit significance increases
//Proof for Windows: 

unsigned int x = 0x01020408; //each hexadecimal digit is 4 bits, meaning there are 2
                             //digits for every byte
char *c = (char *)&x;
unsigned int y = *c*pow(16,0) +pow(16,2) * *(c+1)+pow(16,4) * *(c+2)+pow(16,6) * *(c+3);
//Here's the test: construct the sum y such that we select subsequent bytes of 0x01020408
//in increasing order and then we multiply each by its corresponding significance in
//increasing order.  The convention for hexadecimal number definitions is that  
//the least significant digit is at the right of the number.  
//Finally, if (y==x),then...     
if (y==x) cout<<"Little Endian"<<endl;
else cout<<"Big Endian"<<endl;

cout<<(int) *c<<endl;
cout<<(int) *(c+1)<<endl;
cout<<(int) *(c+2)<<endl;
cout<<(int) *(c+3)<<endl;
cout<<"x is "<<x<<endl;
cout<<(int)*c<<"*1 + "<<(int)*(c+1)<<"*16^2 + "<<(int)*(c+2)<<"*16^4 + "<<(int)*(c+3)<<" *16^6 = "<<y<<endl;
system("PAUSE"); //Only include this on a counsel program
return 0;
}

Это отображает 8 4 2 1 для разыменованных значений в c, c + 1, c + 2 и c + 3 соответственно. Сумма y равна 16909320, что равно x. Несмотря на то, что значение цифр растет справа налево, это все еще Little Endian, потому что соответствующие значения памяти также растут справа налево, поэтому двоичный оператор << сдвига влево << увеличит значение переменной пока ненулевые цифры не будут полностью смещены с переменной. Не путайте этот оператор с оператором << std :: cout. Если бы это был Big Endian, то отображение для c, c + 1, c + 2 и c + 3 соответственно было бы выглядеть так: 1 2 4 8 </p>

...