Является ли чтение одного байта за период независимым от байтов независимо от размера значения? - PullRequest
8 голосов
/ 30 мая 2019

Скажите, что я читаю и записываю uint32_t значения в поток и из него.Если я читаю / записываю по одному байту за раз в / из потока и сдвигаю каждый байт, как показано в приведенных ниже примерах, будут ли результаты согласованы независимо от порядкового номера машины?

В приведенных здесь примерах поток является буфером впамять называется p.

static uint32_t s_read_uint32(uint8_t** p)
{
    uint32_t value;
    value  = (*p)[0];
    value |= (((uint32_t)((*p)[1])) << 8);
    value |= (((uint32_t)((*p)[2])) << 16);
    value |= (((uint32_t)((*p)[3])) << 24);
    *p += 4;
    return value;
}

static void s_write_uint32(uint8_t** p, uint32_t value)
{
    (*p)[0] = value & 0xFF;
    (*p)[1] = (value >> 8 ) & 0xFF;
    (*p)[2] = (value >> 16) & 0xFF;
    (*p)[3] = value >> 24;
    *p += 4;
}

В настоящее время у меня нет доступа к машине с прямым порядком байтов, чтобы проверить это, но идея заключается в том, что каждый байт записывается по одному за раз, каждый отдельный байт можетбыть независимо написанным или прочитанным из потока.Тогда процессор может обрабатывать порядок байтов, скрывая эти детали за операциями сдвига.Это правда, и если нет, то кто-нибудь может объяснить, почему нет?

Ответы [ 2 ]

6 голосов
/ 30 мая 2019

Если я читаю / записываю по одному байту за раз в / из потока и сдвигаю каждый байт, как показано в приведенных ниже примерах, будут ли результаты согласованы независимо от порядкового номера машины?

Да,Ваша функция s_write_uint32() сохраняет байты входного значения в порядке от наименее значимого до наиболее значимого, независимо от их порядка в собственном представлении этого значения.Ваш s_read_uint32() правильно меняет этот процесс, независимо от базового представления uint32_t.Они работают, потому что

  • поведение операторов сдвига (<<, >>) определяется в терминах значения левого операнда, а не его представления
  • & 0xff маскирует все биты левого операнда, кроме битов его младшего байта, независимо от представления значения (поскольку 0xff имеет совпадающее представление), а
  • the |= операции просто помещают байты в результат;позиции выбираются, соответственно, предыдущим левым сдвигом.Это может быть более понятным, если вместо этого использовать +=, но результат не будет отличаться.

Обратите внимание, однако, что в некоторой степени вы заново изобретаете колесо.POSIX определяет пару функций htonl() и nothl() - поддерживаемую также во многих не POSIX-системах - для решения проблем порядка байтов в четырехбайтовых числах.Идея состоит в том, что при отправке каждый использует htonl() для преобразования из байтового порядка хоста (независимо от того, что это) в сетевой байтовый порядок (big endian) и отправляет результирующий четырехбайтовый буфер.По получении каждый принимает четыре байта в одно число, а затем использует ntohl() для преобразования из сети в порядок байтов хоста.

1 голос
/ 31 мая 2019

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

#include <stdint.h>
#include <string.h>

#define LE (((char*)&(uint_least32_t){1})[0]) // little endian ? 
void byteswap(char*,size_t);

uint32_t s2_read_uint32(uint8_t** p)
{
    uint32_t value;
    memcpy(&value,*p,sizeof(value));
    if(!LE) byteswap(&value,4);
    return *p+=4, value;
}

 void s2_write_uint32(uint8_t** p, uint32_t value)
{
    memcpy(*p,&value,sizeof(value));
    if(!LE) byteswap(*p,4);
    *p+=4;
}

Gcc, начиная с 8-й серии (но не лязг), может устранить эти сдвиги на платформах с прямым порядком байтов, но вы должны помочь ему, restrict -квалифицируя двояко-косвенный указатель на пункт назначения, иначе он может подумать, что запись в (*p)[0] может сделать недействительной *p (uint8_t - это тип символа и, следовательно, разрешено псевдонимом чего угодно).

void s_write_uint32(uint8_t** restrict p, uint32_t value)
{
    (*p)[0] = value & 0xFF;
    (*p)[1] = (value >> 8 ) & 0xFF;
    (*p)[2] = (value >> 16) & 0xFF;
    (*p)[3] = value >> 24;
    *p += 4;
}
...