Как данные хранятся на уровне битов в соответствии с «Endianness»? - PullRequest
3 голосов
/ 29 мая 2010

Я читал об Endianness и понял, что приземистый ...

поэтому я написал это

main()
{
    int k = 0xA5B9BF9F;

    BYTE *b = (BYTE*)&k;    //value at *b is 9f
    b++;    //value at *b is BF
    b++;    //value at *b is B9
    b++;    //value at *b is A5
}

k было равно A5 B9 BF 9F

и (байт) указатель " walk " o / p был 9F BF b9 A5

так что я понял, что байты хранятся задом наперед ... хорошо.

~

так что теперь я подумал, как это хранится на уровне BIT ...

I означает, что "9f" (1001 1111) хранится как "f9" (1111 1001)?

поэтому я написал это

int _tmain(int argc, _TCHAR* argv[])
{
    int k = 0xA5B9BF9F;
    void *ptr = &k;
    bool temp= TRUE;
    cout<<"ready or not here I come \n"<<endl;

    for(int i=0;i<32;i++)
    {   
        temp = *( (bool*)ptr + i );
        if( temp )
            cout<<"1 ";
        if( !temp)
            cout<<"0 ";
        if(i==7||i==15||i==23)
            cout<<" - ";
   }
}

Я получаю случайный вывод

даже для номеров как "32", я ничего толкового не понимаю.

почему?

Ответы [ 5 ]

7 голосов
/ 29 мая 2010

Просто для полноты машины описываются в терминах и порядка байтов и битов.

Intel x86 называется Consistent Little Endian, поскольку он хранит многобайтовые значения в порядке от LSB до MSB при увеличении адреса памяти. Соглашение о нумерации битов: b0 = 2 ^ 0 и b31 = 2 ^ 31.

Motorola 68000 называется Inconsistent Big Endian, потому что он сохраняет многобайтовые значения в порядке от MSB до LSB при увеличении адреса памяти. Соглашение о нумерации битов: b0 = 2 ^ 0 и b31 = 2 ^ 31 (то же самое, что и intel, поэтому он называется «Непоследовательный» Big Endian).

32-разрядный IBM / Motorola PowerPC называется Consistent Big Endian, поскольку он сохраняет многобайтовые значения в порядке от MSB до LSB при увеличении адреса памяти. Соглашение о нумерации битов: b0 = 2 ^ 31 и b31 = 2 ^ 0.

При обычном использовании языка высокого уровня порядок битов, как правило, прозрачен для разработчика. При написании на ассемблере или работе с оборудованием, нумерация битов вступает в игру.

5 голосов
/ 29 мая 2010

Порядковый номер , как вы обнаружили в ходе эксперимента, относится к порядку, в котором байты хранятся в объекте.

Биты не хранятся по-разному, они всегда 8 бит и всегда «читаемы человеком» (high-> low).

Теперь, когда мы обсудили, что вам не нужен ваш код ... О вашем коде:

for(int i=0;i<32;i++)
{   
  temp = *( (bool*)ptr + i );
  ...
}

Это не делает то, что вы думаете, что делает. Вы перебираете 0-32, количество бит в слове - хорошо. Но ваше temp задание неверно:)

Важно отметить, что bool* имеет тот же размер, что и int*, тот же самый размер, что и BigStruct*. Все указатели на одной машине имеют одинаковый размер - 32 бита на 32-битной машине, 64 бита на 64-битной машине.

ptr + i добавляет i байт к адресу ptr. Когда i>3, вы читаете целое новое слово ... это может привести к segfault.

То, что вы хотите использовать, это бит-маски . Примерно так должно работать:

for (int i = 0; i < 32; i++) {
  unsigned int mask = 1 << i;
  bool bit_is_one = static_cast<unsigned int>(ptr) & mask;
  ...
}
3 голосов
/ 29 мая 2010

байтовый порядок байтов

На разных машинах этот код может давать разные результаты:

union endian_example {
   unsigned long u;
   unsigned char a[sizeof(unsigned long)];
} x;

x.u = 0x0a0b0c0d;

int i;
for (i = 0; i< sizeof(unsigned long); i++) {
    printf("%u\n", (unsigned)x.a[i]);
}

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

Бит Endianness

Обычно вам не нужно беспокоиться о порядке байтов. Наиболее распространенный способ доступа к отдельным битам - сдвиги (>>, <<), но они действительно связаны со значениями, а не байтами или битами. Они предварительно выполняют арифметическую операцию над значением. Это значение хранится в битах (в байтах).

Где вы можете столкнуться с проблемой в C с порядком байтов, если вы когда-либо используете битовое поле. Это редко используемая (по этой и некоторым другим) «функциям» C, позволяющая сообщать компилятору, сколько битов будет использовать член struct.

struct thing {
     unsigned y:1; // y will be one bit and can have the values 0 and 1
     signed z:1; // z can only have the values 0 and -1
     unsigned a:2; // a can be 0, 1, 2, or 3
     unsigned b:4; // b is just here to take up the rest of the a byte
};

В этом порядке байтов зависит от компилятора. Должен ли y быть наиболее или наименее значимым битом в thing? Кто знает? Если вы заботитесь о порядке следования битов (описывая такие вещи, как расположение заголовка пакета IPv4, управляющие регистры устройства или просто формат хранилища в файле), то вам, вероятно, не стоит беспокоиться о том, что какой-то другой компилятор сделает это неправильно путь. Кроме того, компиляторы не всегда так умны в работе с битовыми полями, как можно было бы надеяться.

3 голосов
/ 29 мая 2010

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

Чтобы ваша вторая программа имела смысл (хотя на самом деле нет никаких причин, так как она не даст вам сколько-нибудь значимых результатов), вам нужно узнать о побитовых операторах - особенно & для этого приложения.

2 голосов
/ 29 мая 2010

Эта строка здесь:

temp = *( (bool*)ptr + i );

... когда вы выполняете арифметику указателей, как это, компилятор перемещает указатель на число, которое вы добавили в раз от размера объекта, на который вы указываете . Поскольку вы преобразуете void * в bool *, компилятор будет перемещать указатель на величину, равную одному «bool», который, вероятно, представляет собой целое число int под одеялом, поэтому вы будете распечатывать память дальше чем ты думал.

Вы не можете адресовать отдельные биты в байте, поэтому почти бессмысленно спрашивать, в каком направлении они хранятся. (Ваша машина может хранить их так, как захочет, и вы не сможете сказать). Единственный случай, когда вы можете позаботиться об этом, - это когда вы на самом деле выплевываете биты через физический интерфейс, такой как I2C или RS232 или подобный, где вы должны фактически выплевывать биты один за другим. Даже тогда, однако, протокол будет определять, в каком порядке выводить биты, и код драйвера устройства должен будет переводить между «int со значением 0xAABBCCDD» и «битовой последовательностью 11100011 ... [что угодно] в порядке протокола ».

...