#c #arrays #string #serialization
Вопрос:
в программе на языке Си у меня есть длинный*, который я хочу сериализовать (таким образом, преобразовав в символы). Длинный не помещается в один символ, и размер варьируется в зависимости от процессора (может составлять 4 байта или 8 байт).
Есть хороший способ сделать сериализацию и десериализацию?
Ответ №1:
Это портативно, но далеко не так неэффективно, как использование printf/scanf
void longtochar(char *buffer, unsigned long number) {
int i;
for (i=0; i<sizeof(long); i ) {
buffer[i] = number amp; 0xFF; // place bottom 8 bits in char
number = number >> 8; // shift down remaining bits
}
return; // the long is now stored in the first few (2,4,or 8) bytes of buffer
}
И распаковать его снова (при условии, что длина такого же размера)
long chartolong(char *buffer) {
long number = 0;
int i;
for (i=sizeof(long)-1; i>=0; i--) {
number = number << 8; // left shift bits in long already
number = buffer[i]; // add in bottom 8 bits
}
return number;
}
Обратите внимание на БОЛЬШОЕ предположение, что длина одинакова в обеих системах. Безопасно сделать это #включить <stdint.h> и использовать типы, которые он предоставляет (uint32_t или uint16_t).
Кроме того, в моем коде он указан как длинный без знака. У меня сейчас нет доступа к компилятору C, поэтому я не могу подтвердить, будет ли он работать со знаковыми целыми числами или нет. Если мне не изменяет память, поведение этого может быть неопределенным (хотя, возможно, не имеет значения, как я с этим справляюсь).
Ответ №2:
Скорее всего, вы решаете не ту проблему. Вы должны сериализоваться до фиксированного размера int, например, используя int32_t. Вероятно, вы захотите использовать этот тип фиксированного размера во всей своей программе, или у вас возникнут проблемы, когда 64-разрядная программа не сможет сохранить файл меньшего размера (или использовать int64_t).
Если вы знаете, что вам никогда не придется загружать 64-разрядные сохранения на 32-разрядную платформу, то не беспокойтесь. Просто запишите в файл размер(длинные) байты и считайте обратно размер(длинные) байты. Но поставьте флажок в начале ваших данных, указывающий на исходную платформу, чтобы избежать ошибок.
Ответ №3:
Вам не нужно сериализовываться как символы — вы можете записывать как длинные (в файл). Для сериализации в массив символов вложите байт в начале, чтобы указать размер int и порядок байтов — это вам понадобится позже.
т.е.
char *p = amp;long_array[0];
Чтобы получить доступ к длинному массиву в виде символа, просто приведите его — и умножьте длину массива на sizeof(длинный), чтобы получить размер в символах.
Простой пример иллюстрирует это:
#include <stdio.h>
main()
{
int aaa[10];
int i;
char *p;
for(i=0;i<sizeof(aaa)/sizeof(aaa[0]);i )
{
aaa[i] = i;
printf ("setting aaa[%d] = %8xn",i,aaa[i]);
}
aaa[9] = 0xaabbccdd;
printf ("sizeof aaa (bytes) :%dn",sizeof(aaa));
printf ("each element of aaa bytes :%dn",sizeof(aaa[0]));
p = (char*) aaa;
for(i=0;i<sizeof(aaa);i )
printf ("%d: %8xn",i,(unsigned char)p[i]);
}
Ответ №4:
long * longs;
// ...
int numChars = numLongs * sizeof(long);
char* longsAsChars = (char*) longs;
char* chars = malloc(numChars);
memcpy(chars, longsAsChars, numChars);
Комментарии:
1. Почему нет? Я думаю, что он всегда должен работать в соответствии со спецификациями.
2. с каких это пор «новое» разрешено в C?
3. Предполагая, что вы сериализуетесь для отправки по сети. Компьютер на другом конце может иметь другой размер long. У лонга может быть другой конец и т. Д.
4. Архитектуры: автор на самом деле не хотел сериализовать, просто преобразуйте его в байты в памяти. новинка: с этим не поспоришь.
5. @Лев: Зачем тогда вообще делать копию? Просто наведите указатель на длинный*. Все готово. В приведенном выше коде просто передайте «longAsChars» в качестве результата.
Ответ №5:
В C вы можете получить размер длинного с
sizeof(long)
Но если ваша сохраненная длина должна передаваться между несколькими платформами, вы должны всегда сериализовать ее как 4 байта. Большие числа все равно не могли быть прочитаны 4-байтовым процессором.
Ответ №6:
Если вы создадите указатель на символ, который указывает на начало длинного массива, при увеличении через символ «массив» вы получите 8 бит за раз. Однако имейте в виду, что long не будет завершаться нулем (обязательно, это может быть), поэтому вам нужно отслеживать, где его конец.
Например:
long list[MAX];
char *serial = list;
int chunk = sizeof(long);
int k;
for(k=0; k<(MAX*chunk); k ){
// do something with the "char"
}