Как кодировать числовое значение в байтах - PullRequest
0 голосов
/ 10 сентября 2011

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

Числа до 64 бит, т.е. требуют до 8 байтов. Самый первый байт - это тип, и это всегда число до 255, поэтому помещается в 1 байт.

Например, если число было 8, а типом было 32-разрядное целое число без знака, тогда типом будет 7, который будет скопирован в первый (самый левый) байт, а затем следующие 4 байта будут закодированы с фактическим числом (В данном случае 8).

То есть в байтах:

byte1: 7
byte2: 0
byte3: 0
byte4: 0
byte5: 8

Надеюсь, это имеет смысл.

Этот код для выполнения этой кодировки выглядит как разумный подход?

int type = 7;
uint32_t number = 8;

unsigned char* msg7 = (unsigned char*)malloc(5);
unsigned char* p = msg7;

*p++ = type;

 for (int i = sizeof(uint32_t) - 1; i >= 0; --i) 
    *p++ = number & 0xFF << (i * 8);  

Ответы [ 4 ]

3 голосов
/ 10 сентября 2011

Вы хотите явно привести type, чтобы избежать предупреждения:

*p++ = (unsigned char) type;

Сначала вы хотите закодировать число старшим значащим байтом, но вы перемещаетесь в неправильном направлении. Цикл должен быть:

for (int i = sizeof(uint32_t) - 1; i >= 0; --i)
    *p++ = (unsigned char) ((number >> (i * 8)) & 0xFF);

В противном случае выглядит хорошо.

0 голосов
/ 10 сентября 2011

Я бы отбросил цикл и использовал бы интерфейс "вызывающего абонента", например

int convert_32 (unsigned char *target, size_t size, uint32_t val)
{
if (size < 5) return -1;

target[0] = 7;
target[1] = (val >> 24) & 0xff;
target[2] = (val >> 16) & 0xff;
target[3] = (val >> 8) & 0xff;
target[4] = (val) & 0xff;

return 5;
}

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

0 голосов
/ 10 сентября 2011

Ваш код является разумным (хотя я бы использовал uint8_t, поскольку вы не используете байты в качестве «символов», а Питер, конечно, прав в отношении опечатки), и в отличие от часто встречающихся альтернатив, таких как

uint32_t number = 8;
uint8_t* p = (uint8_t *) &number;

или

union {
  uint32_t number;
  uint8_t bytes[4];
} val;
val.number = 8;
// access val.bytes[0] .. val.bytes[3]

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

0 голосов
/ 10 сентября 2011

Вы имеете в виду?

for (int i = sizeof(uint32_t) - 1; i >= 0; --i)
  *p++ = (number >> (i * 8)) & 0xFF; 

Другим вариантом может быть

// this would work on Big endian systems, e.g. sparc
struct unsignedMsg {
    unsigned char type;
    uint32_t value;
}

unsignedMsg msg;
msg.type = 7;
msg.value = number;
unsigned char *p = (unsigned char *) &msg;

или

unsigned char* p = 
p[0] = 7;
*((uint32_t *) &(p[1])) = number;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...