Сериализация длинного массива (в C)

#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"
}