C, Little и Big Endian путаница - PullRequest
       10

C, Little и Big Endian путаница

0 голосов
/ 06 февраля 2019

Я пытаюсь понять порядок байтов памяти C, но я запутался.Я пробую мое приложение с некоторым значением на этом сайте для проверки вывода: www.yolinux.com / TUTORIALS / Endian-Byte-Order.html

Для 64-битного значения Iиспользовать в моей программе на C:

volatile long long ll = (long long)1099511892096;
__mingw_printf("\tlong long, %u Bytes, %u bits,\t%lld to %lli, %lli, 0x%016llX\n", sizeof(long long), sizeof(long long)*8, LLONG_MIN, LLONG_MAX , ll, ll);

void printBits(size_t const size, void const * const ptr)
{
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i, j;
    printf("\t");
    for (i=size-1;i>=0;i--)
    {
        for (j=7;j>=0;j--)
        {
            byte = b[i] & (1<<j);
            byte >>= j;
            printf("%u", byte);
        }

        printf(" ");
    }
    puts("");
}

Out

long long,                8 Bytes,   64 bits,   -9223372036854775808 to 9223372036854775807, 1099511892096, 0x0000010000040880
80 08 04 00 00 01 00 00  (Little-Endian)
10000000 00001000 00000100 00000000 00000000 00000001 00000000 00000000
00 00 01 00 00 04 08 80  (Big-Endian)
00000000 00000000 00000001 00000000 00000000 00000100 00001000 10000000

Тесты

0x8008040000010000, 1000000000001000000001000000000000000000000000010000000000000000 // online website hex2bin conv. 
                    1000000000001000000001000000000000000000000000010000000000000000 // my C app
0x8008040000010000, 1000010000001000000001000000000000000100000000010000000000000000 // yolinux.com


0x0000010000040880, 0000000000000000000000010000000000000000000001000000100010000000      //online website hex2bin conv., 1099511892096  ! OK
                    0000000000000000000000010000000000000000000001000000100010000000      // my C app,  1099511892096 ! OK
[Convert]::ToInt64("0000000000000000000000010000000000000000000001000000100010000000", 2) // using powershell for other verif., 1099511892096 ! OK          
0x0000010000040880, 0000000000000000000000010000010000000000000001000000100010000100      // yolinux.com, 1116691761284 (from powershell bin conv.) ! BAD !

Проблема

Сайт yolinux.com анонсирует 0x0000010000040880 для BIG ENDIAN !Но мой компьютер использует LITTLE ENDIAN, я думаю (Intel proc.), И я получаю то же значение 0x0000010000040880 из моего приложения C и из другого конвертера hex2bin веб-сайта.__mingw_printf (... 0x% 016llX ..., ... ll) также печатает 0x0000010000040880, как вы можете видеть.

После сайта yolinux я перевернул мои "(Little-Endian)" и "(Big-Endian) "помечены в моем выводе на данный момент.

Кроме того, бит знака должен быть 0 для положительного числа, это дело моего результата, но также и результата yolinux. (Не может помочь мне быть уверенным.)

Если я правильно понимаю, что Endianness меняются только байты, а не биты, и мои группы битов, похоже, правильно инвертированы.

Это просто ошибка на yolinux.com или я пропускаю шаг по поводу64-битные числа и программирование на C?

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Существует только один способ представления целого числа в десятичном, двоичном или шестнадцатеричном формате.Например, число 43981 равно 0xABCD при записи в шестнадцатеричном формате или 0b1010101111001101 в двоичном виде.Любое другое значение (0xCDAB, 0xDCBA или подобное) представляет другое число.

То, как ваш компилятор и процессор решают хранить это значение внутренне, не имеет значения, если речь идет о стандарте C;значение может быть сохранено как 36-битное дополнение , если вам особенно не повезло, если все операции, предусмотренные стандартом, имеют эквивалентные эффекты.

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

// input value is big endian, this is defined
// by the communication protocol

uint32_t parse_comm_value(const char * ptr)
{
     // but bit shifts in C have the same
     // meaning regardless of the endianness
     // of your architecture

     uint32_t result = 0;
     result |= (*ptr++) << 24;
     result |= (*ptr++) << 16;
     result |= (*ptr++) << 8;
     result |= (*ptr++);
     return result;
}

Tl; dr, вызывающий стандартную функцию, такую ​​как printf("0x%llx", number);, всегда печатает правильное значение, используя указанный формат.Проверка содержимого памяти путем считывания отдельных байтов дает представление данных о вашей архитектуре.

0 голосов
/ 06 февраля 2019

Когда вы печатаете какое-то «многобайтовое» целое число, используя printf (и правильный спецификатор формата), не имеет значения, является ли система младшим или старшим.Результат будет таким же.

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

Этот код показывает, как целое число (4 байта) помещается в память на моем компьютере.

#include <stdio.h>

int main()
{
    unsigned int u = 0x12345678;
    printf("size of int is %zu\n", sizeof u);
    printf("DEC: u=%u\n", u);
    printf("HEX: u=0x%x\n", u);
    printf("memory order:\n");
    unsigned char * p = (unsigned char *)&u;
    for(int i=0; i < sizeof u; ++i) printf("address %p holds %x\n", (void*)&p[i], p[i]);
    return 0;
}

Вывод:

size of int is 4
DEC: u=305419896
HEX: u=0x12345678
memory order:
address 0x7ffddf2c263c holds 78
address 0x7ffddf2c263d holds 56
address 0x7ffddf2c263e holds 34
address 0x7ffddf2c263f holds 12

Итак, я вижу, что я нахожусь на машине с прямым порядком байтов, поскольку младший байт (т.е. младший байт, т.е. 78) хранится по младшему адресу.

Выполнениета же программа на машине с прямым порядком байтов показала бы (при условии того же адреса):

size of int is 4
DEC: u=305419896
HEX: u=0x12345678
memory order:
address 0x7ffddf2c263c holds 12 
address 0x7ffddf2c263d holds 34 
address 0x7ffddf2c263e holds 56 
address 0x7ffddf2c263f holds 78 

Теперь это MSB (старший байт, т.е. 12), который хранится по младшему адресу.

Важно понимать, что только относится к тому, «как многобайтовый тип хранится в памяти».После того, как целое число будет считано из памяти в регистр внутри ядра, регистр будет содержать целое число в форме 0x12345678 на на как на младших, так и на старших порядковых машинах.

...