Распаковка целого числа из байтового массива - PullRequest
0 голосов
/ 08 января 2019

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

Определения типов в примере:

uint8_t *dest;
uint8_t *ciphertext;
size_t  cbytes; // length of ciphertext
uint8_t iv[16];
uint8_t tag[16];

Соответствующая часть автора:

size_t bytes = 0;
memcpy(&dest[bytes], iv, sizeof(iv));
bytes = sizeof(iv);
memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));
bytes += sizeof(uint32_t);
memcpy(&dest[bytes], ciphertext, cbytes);
bytes += cbytes;
memcpy(&dest[bytes], tag, sizeof(tag));
bytes += sizeof(tag);

Это правильный способ ввода cbytes, как целого числа в байтовый массив? Если нет, то как лучше это сделать?

Теперь, с этим байтовым массивом, как мне прочитать cbytes обратно в целое число (или size_t)? Остальное можно скопировать обратно, но не уверен, что делать с целым числом.

1 Ответ

0 голосов
/ 08 января 2019

Вы спрашиваете об этом куске кода:

memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));

Нет, это совсем не правильно. Вы конвертируете возвращаемое значение htonl в указатель. Однако это неверный указатель. У вас есть , чтобы иметь объект типа uint32_t для отправки:

uint32_t cbytes32 = htonl(cbytes);
memcpy(&dest[bytes], &cbytes32, sizeof(uint32_t));

Это можно сделать и в одну строку, в современном C, используя составной литерал , чтобы создать массив из одного uint32_t inline:

memcpy(&dest[bytes], (uint32_t[]){ htonl(cbytes) }, sizeof(uint32_t));

но синтаксис действительно не выглядит лучше.

Чтобы прочитать его, вам нужно прочитать его для объекта типа uint32_t, затем ntohl его и возвращаемого значения, которое вы можете сохранить в size_t:

uint32_t size32;
size_t size;
memcpy(&size32, src, sizeof size32)
size = ntohl(size32);

Тогда я был бы особенно осторожен с тем, что вы используете, возможно, 64-битный size_t в другом месте, но урезаете его до 32 бит. Это может быть хорошо, но это должно быть задокументировано. 64 бита должно хватить всем, но, к сожалению, функции htonll нет.


Наконец, вместо &dest[bytes] вы можете написать dest + bytes для меньшего количества нажатий клавиш. И еще меньше, вы можете сделать еще один указатель:

uint8_t *cur = dest;
memcpy(cur, iv, sizeof iv);
cur += sizeof iv;
uint32_t cbytes32 = htonl(cbytes);
memcpy(cur, &cbytes32, sizeof cbytes32);
cur += sizeof cbytes32;
memcpy(cur, ciphertext, cbytes32);
cur += cbytes32;
memcpy(cur, tag, sizeof tag);
cur += sizeof tag;
size_t nbytes = cur - dest;

Обратите внимание, что если вы используете потоковый сокет (TCP), обычно нет необходимости копировать их в промежуточный буфер - просто отправьте 4, 8 байтов, используя отдельный вызов read - или, по крайней мере, не пытайтесь копировать массив long в тот же буфер после вызова размера.

...