Little vs Big Endianess: как интерпретировать тест

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

вот что я нашел в интернете. Что означает *(char *)&x и как он равен одному, доказывает, что машина мало-конечна?

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

6 ответов


если мы разделимся на разные части:

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

  2. (char *)&x: Это принимает адрес x (это int *) и преобразует его в char *.

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

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

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


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

Little-endian
0x01000000 = 00000001000...00

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

разыменование char * дает вам один байт. Ваш тест извлекает первый байт в этом месте памяти с помощью интерпретация адреса как char * а затем разыменовать его.


разрушение *(char *)&x:

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

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

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


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 is 0x100.

(char *)&x 

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

*(char *)&x 

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

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

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


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

#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;
}

откроется Восемь Четыре Два Один для значений разыменован на С, с+1, с+2 и с+3 соответственно. Сумма y равна 16909320, что равно x. Несмотря на то, что значение цифр растет справа налево, это все еще немного Эндиан, потому что соответствующие значения памяти также растут справа налево, поэтому двоичный оператор сдвига влево


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

Если Биг-эндианский 2-байтовый unsigned short выглядит как 0xAABB, который равен 43707, то тот же 2-байтовый unsigned short выглядит как 0xBBAA на мало-эндианском процессоре, который также равен 43707.

вот несколько удобных #define функции для обмена байтами с little-endian на big-endian и наоборот -->

// 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))