Как использовать гибкие элементы массива во вложенных структурах C?

Связано: гибкий член массива во вложенной структуре

Я пытаюсь разобрать некоторые данные в структуру. Данные содержат информацию, организованную следующим образом:

struct unit {

    struct unit_A {
        // 28 bytes each

        // dependency r6scA 1
        char dr6scA1_tagclass[4];
        uint32_t dr6scA1_tagnamepointer;
        uint32_t dr6scA1_tagnamestringlength;
        uint32_t dr6scA1_tagid;

        // 12 bytes of 0x00

    }A;

    // A strings

    struct unit_B {
        // 48 bytes each

        // dependency r6scB 1
        char dr6scB1_tagclass[4];
        uint32_t dr6scB1_tagnamepointer;
        uint32_t dr6scB1_tagnamestringlength;
        uint32_t dr6scB1_tagid;

        // 32 bytes of 0x00

    }B;

    // B strings

    // unit strings

}unit_container;

Вы можете игнорировать странную номенклатуру.

Мои строковые комментарии // A strings, // B strings и // unit strings содержат строки C с завершающим нулем, номера которых совпадают с количеством записей структур unit_A, unit_B и unit в данных. Например, если есть 5 записей A в unit_container, тогда будет 5 строк C в том месте, где написано // A strings.

Поскольку я не могу использовать гибкие элементы массива в этих местах, как мне интерпретировать то, что по сути является неизвестным количеством строк C переменной длины в этих местах данных?

Например, данные в этих местах могут быть:

«Первая запись здесь. \ 0 Вторая запись \ 0Другая! \ 0Четвертая. \ 0Эта 5-я запись - лучшая запись по любым разумным стандартам. \ 0»

... что, как я полагаю, следует интерпретировать как:

char unit_A_strings[]

... но это невозможно. Какие у меня варианты?

Спасибо за внимание.

РЕДАКТИРОВАТЬ:

Я считаю, что пока что наиболее привлекательным вариантом является:

char** unit_A_strings;, чтобы указать на массив строк символов.

Если я сделаю: char unit_A_strings[1];, чтобы определить массив символов фиксированного размера из 1 символа, тогда я должен отказаться от sizeof (unit) и тому подобное, или возиться с размерами выделения памяти, даже если это наиболее точно соответствует типу имеющихся данных. То же самое произойдет, если я сделаю char * unit_A_strings[1];.

Другой вопрос: В чем разница между использованием char *unit_A_strings; и char** unit_A_strings;?

Вывод:

Основная проблема заключается в том, что структуры предназначены для информации фиксированного размера, а мне нужна область памяти информации переменного размера. Поэтому я не могу законно хранить данные в структуре - по крайней мере, не как структуру. Это означает, что подойдет любая другая интерпретация, и мне кажется, что char** - лучший доступный вариант для этой ситуации со структурой.


person silent    schedule 12.06.2016    source источник
comment
Я добавил второй вопрос, потому что похоже, что char** или незаконный char* - мои лучшие варианты.   -  person silent    schedule 12.06.2016
comment
В чем будет разница между использованием char unit_A_strings; и char * unit_A_strings ;? Первый является указателем на (массив из?) chars. Последний является указателем на (массив из?) char *s. Они принципиально разные. Независимо от того, является ли это массив или нет, зависит от вас - и нормальный способ завершения массива - иметь конечное значение 0 / NULL.   -  person John Burger    schedule 12.06.2016
comment
Я ценю вашу помощь! Я бы проголосовал за оба ваших ответа, если бы мог.   -  person silent    schedule 12.06.2016


Ответы (2)


Я думаю, что он может использовать вместо этого char ** (или вы можете написать некоторую структуру, чтобы обернуть его). например, вы можете написать вспомогательную функцию для декодирования вашего потока.

char** decodeMyStream(uint_8* stream, unsigned int* numberOfCString)
{
    *numberOfCString = decodeNumberOfCString(stream);
    char** cstrings = malloc((*numberOfCString) * sizeof(char*));
    unsigned int start = 0;
    for (unsigned int i = 0; i < *numberOfCString; ++i)
    {
        usigned int len = calculateIthStringLength(stream, start)
        cstrings[i] = malloc((len) * sizeof(char));
        memcpy(cstrings[i], stream + start, len); 
        start += len
    }
    return cstrings;
}

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

person jstar    schedule 12.06.2016
comment
Что вы думаете об использовании char *unit_A_strings для указания адреса первого символа, а затем просто об использовании функции для идентификации остальных char * строк после этого? Является ли использование char **unit_A_strings более подходящим для использования массива строк? - person silent; 12.06.2016
comment
Я думаю, что это тоже работает, и если вы тщательно обернете функцию, это может быть даже элегантным. - person jstar; 12.06.2016
comment
например: char * s = aaaa \ 0bbbb \ 0; тогда вы можете написать следующий код: unsigned int len ​​= strlen (s); char * firstStr = s; char * secondStr = s + len; Я думаю, вы можете хорошенько подумать о структуре данных, чтобы сохранить эти строки, и о цикле, как декодировать эти строки. - person jstar; 12.06.2016

Я думаю, что самое близкое, что вы получите, - это предоставить массив строк:

char *AStrings[] = { "The first entry is here.",
                     "Second entry",
                     "Another!",
                     "Fourth.",
                     "This 5th entry is the bestest entry evah by any reasonable standards.",
                     NULL
                   };

Обратите внимание на две вещи:

  1. AStrings - это массив указателей на строки - это будет 6 (см. 2. ниже) последовательных указателей, которые указывают на фактические строки, а НЕ на «составную» строку, которую вы использовали в своем примере.
  2. Я закончил AStrings указателем NULL, чтобы решить вопрос «когда мне закончить?» вопрос.

Таким образом, вы можете «упасть с конца» A и начать смотреть на места как на указатели, но будьте осторожны! Компилятор может вставлять всевозможные отступы между одной переменной и другой, опровергая любые предположения о том, где они находятся относительно друг друга в памяти, включая их переупорядочивание!

Изменить. Я просто подумал. Другое представление данных, которое может помочь, - это, по сути, то, что вы сделали. Я немного его "приукрасил":

char AString[] = "The first entry is here.\0"
                 "Second entry\0"
                 "Another!\0"
                 "Fourth.\0"
                 "This 5th entry is the bestest entry evah by any reasonable standards.\0";
  • Компилятор C автоматически объединит две «соседние» строки, как если бы они были одной строкой, с символом нет NUL между ними. Я поместил их специально выше.
  • Компилятор C автоматически помещает '\0' в конец любой строки - в точку с запятой (;) в приведенном выше примере. Это означает, что строка фактически заканчивается двумя символами NUL, а не одним.

Вы можете использовать этот факт, чтобы отслеживать, где вы находитесь, при анализе строкового «массива» - предполагая, что каждое желаемое значение имеет (под) строку более нулевой длины! Как только вы сталкиваетесь с (под) строкой нулевой длины, вы знаете, что достигли конца строкового «массива».

Я называю такие строки строками ASCIIZZ (строки ASCIIZ со вторым NUL в конце всех).

person John Burger    schedule 12.06.2016
comment
Мне интересно, что поместить в структуру в комментариях строки A strings, B strings и unit strings. Итак, вы говорите, что я мог бы использовать char [] в этих местах. Данные уже заданы: несколько строк с завершающим нулем одна за другой. Я не могу определять строки сам, скорее, я просто пытаюсь разобрать их в структуру. - person silent; 12.06.2016
comment
И проблема в том, что я не могу использовать char [] в качестве гибкого члена массива, мне пришлось бы сделать что-то вроде char AString[1];, но это не соответствует размеру данных. - person silent; 12.06.2016
comment
Жалко, что нельзя использовать FAM - но тоже облегчение. Они грязные! Да, я говорю, что вы должны иметь возможность помещать char[] сразу после экземпляра struct и надеяться, что компилятор обработает его «нормально». Однако вам придется выполнить синтаксический анализ самостоятельно во время выполнения - или использовать более ранний массив-of-char [], который я дал - person John Burger; 12.06.2016
comment
Что насчет чего-то вроде char *AString;, а затем просто указания на первую строку? Таким образом, если нет никаких струн, у меня не возникнет затруднений. - person silent; 12.06.2016
comment
Теперь я путаюсь между двумя возможными решениями! У вас может быть один член в вашей структуре, который либо указывает на строку ASCIIZZ с помощью char *, либо указывает на массив строк с помощью char * * - оба будут работать, и последнее будет проще. - person John Burger; 12.06.2016