Это зависит от того, насколько общим должно быть ваше решение.Как выяснили другие ответы, две примерные структуры чрезвычайно похожи, и поэтому ими можно относительно легко управлять (хотя решение о том, как определить конец строки символов, представляет некоторые проблемы).
Если вам нужен более общийсистема, вам, вероятно, потребуется посмотреть какую-то строку «структурный дескриптор», которую вы передаете в конвертер, или, возможно, «массив структурных дескрипторов».
Например, строки могут быть:
"i s16 i i i i" // typeA
"i s32 i i i i" // typeB
"u32 i64 z d d" // struct { uint32_t a; int64_t b; size_t c; double d; double e; };
int parse_any_type(void *output, const char *desc);
Затем вам придется столкнуться с некоторыми проблемами выравнивания и дополнения, но (если вы получите правильные строки дескриптора), вы можете написать подпрограмму для обработки этого лота (упакованную или распакованную).
Используя 'дескрипторы', вы, вероятно, имеете дело с одним из менее известных макросов в C, макросом offsetof
, определенным в <stddef.h>
.Вы должны создать тип дескриптора, такой как:
enum Type { CHAR, UCHAR, SCHAR, STR, USTR, SSTR, SHORT, USHORT, INT, UINT, LONG, ULONG, ... };
struct descriptor
{
enum Type m_type; // Code for the variable type
size_t m_size; // Size of type
size_t m_offset; // Offset of variable in structure
};
struct descriptor d_TypeA[] =
{
{ INT, sizeof(int), offsetof(TypeA, id) },
{ STR, 16, offsetof(TypeA, name) },
{ INT, sizeof(int), offsetof(TypeA, value1) },
{ INT, sizeof(int), offsetof(TypeA, value2) },
{ INT, sizeof(int), offsetof(TypeA, value3) },
{ INT, sizeof(int), offsetof(TypeA, value4) },
};
Затем вы можете передать соответствующий массив дескрипторов типов (и размер этого массива) в функцию вместе с указателем на то, куда должны быть переданы данные.быть сохраненным.
Вместо использования перечисления вы можете использовать тип указателя на функцию, который указывает на правильный преобразователь.
int parse_structure(void *output, const struct descriptor *desc, size_t n_desc);
Другой альтернативой является то, что вы просто имеете дело с каждым типом с помощьюсоответствующая функция, которая вызывает другие более простые функции для обработки каждого элемента структуры.
int parse_TypeA(TypeA *output)
{
if (parse_int(&output->id) == 0 &&
parse_str(output->name, 16) == 0 &&
parse_int(&output->value1) == 0 &&
parse_int(&output->value2) == 0 &&
parse_int(&output->value3) == 0 &&
parse_int(&output->value4) == 0)
return 0;
...diagnose error...
return -1;
}
В ваших примерах неясно указано, откуда поступают данные, а не где они должны храниться.Это может не иметь значения, но повлияет на решение.Без аргументов может быть разумным ожидать, что данные будут считаны из стандартного ввода.В качестве альтернативы, у вас может быть строка, содержащая данные для анализа, возможно, тоже с длиной;это будут аргументы функции.
В ваших примерах не проиллюстрирована обработка ошибок;как вызывающий код узнает, было ли преобразование успешным или нет.
Если все сделано правильно, один и тот же механизм описания может использоваться как для синтаксического анализа, так и для механизмов печати - ваша функция parse_any_type()
больше похожа на печатьфункция.
См. также