Невозможно динамически определить структуру, идентичную структуре времени компиляции.
Возможно, но сложно создать динамические структуры, которые могут содержать информацию, эквивалентную структуре. Доступ к данным менее удобен, чем тот, который доступен во время компиляции.
Кроме всего прочего, вы не можете получить доступ к члену somestruct.not_seen_at_compile_time
, используя нотацию .
или ->
, если она не была определена во время компиляции.
С сетевыми коммуникациями есть и другие проблемы, в частности, «порядковый номер». То есть данные на проводе, вероятно, будут включать многобайтовые (2, 4, 8) целые числа, и MSB или LSB будут отправляться первыми, но если один из них имеет младший порядок (IA-32, IA- 64, x86 / 64), а другой - с прямым порядком байтов (SPARC, PPC, почти все, что не от Intel), тогда данные нужно будет преобразовать. Форматы с плавающей точкой также могут быть проблематичными. Существует множество стандартов, посвященных определению того, как данные будут передаваться по сети, - это не тривиально. Некоторые из них являются конкретными: IP, TCP, UDP; другие носят общий характер, например, ASN.1.
Однако, часть «не может создавать динамические структуры данных» ограничивает вещи - вы должны заранее договориться о том, что такое структуры данных и как они будут интерпретироваться.
Как ты это делаешь?
gerty3000 спрашивает:
Возможно, но сложно создать динамические структуры, которые могут содержать информацию, эквивалентную структуре. - Как вы это делаете? Я хотел бы передать динамически определенные структуры в другой код C (предположим, тот же компилятор и другие параметры) без необходимости дублировать процедуры компоновки структуры памяти из компилятора. Я не буду часто обращаться к полям этих структур внутри моего процесса (просто инициализирую их один раз), поэтому удобный синтаксис не имеет значения.
Вы не сможете сделать это, не продублировав макет памяти в той или иной форме. Возможно, это не должно быть точно так же, но, вероятно, лучше, если это так. Вот пример кода, который примерно показывает, как это можно сделать.
dynstruct.c
Содержит основную структуру манипулирования материалом - структуры для описания структур и (простых) элементов. Обработка полных массивов (в отличие от строк) потребует больше работы, и для других типов необходимо выполнить большую часть репликации с заданиями.
Он также содержит main()
программу, которая тестирует код. Он вызывает other_function()
, что демонстрирует, что структура, которую я определил в структурах данных, точно соответствует структуре. Данные предполагают 64-битный компьютер, где double
должен быть выровнен по 8-байтовой границе (так что в структуре есть 4-байтовое отверстие); вам придется настроить данные для машины, где double
может находиться на 4-байтовой границе.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This is the type that will be simulated dynamically */
/*
struct simulated
{
int number;
double value;
char string[32];
};
*/
/* SOF structure.h */
typedef enum Type { INT, DOUBLE, STRING } Type;
typedef struct Descriptor
{
size_t offset;
Type type;
size_t type_size;
size_t array_dim;
char name[32];
} Descriptor;
typedef struct Structure
{
size_t size;
char name[32];
Descriptor *details;
} Structure;
extern void *allocate_structure(const Structure *structure);
extern void deallocate_structure(void *structure);
extern void *pointer_to_element(void *p, const Descriptor *d);
extern int get_int_element(void *p, const Descriptor *d);
extern void set_int_element(void *p, const Descriptor *d, int newval);
extern double get_double_element(void *p, const Descriptor *d);
extern void set_double_element(void *p, const Descriptor *d, double newval);
extern char *get_string_element(void *p, const Descriptor *d);
extern void set_string_element(void *p, const Descriptor *d, char *newval);
/* EOF structure.h */
static Descriptor details[] =
{
{ 0, INT, sizeof(int), 1, "number" },
{ 8, DOUBLE, sizeof(double), 1, "value" },
{ 16, STRING, sizeof(char), 32, "string" },
};
static Structure simulated = { 48, "simulated", details };
void *allocate_structure(const Structure *structure)
{
void *p = calloc(1, structure->size);
return p;
}
void deallocate_structure(void *structure)
{
free(structure);
}
void *pointer_to_element(void *p, const Descriptor *d)
{
void *data = (char *)p + d->offset;
return data;
}
int get_int_element(void *p, const Descriptor *d)
{
assert(d->type == INT);
int *v = pointer_to_element(p, d);
return *v;
}
void set_int_element(void *p, const Descriptor *d, int newval)
{
assert(d->type == INT);
int *v = pointer_to_element(p, d);
*v = newval;
}
double get_double_element(void *p, const Descriptor *d)
{
assert(d->type == DOUBLE);
double *v = pointer_to_element(p, d);
return *v;
}
void set_double_element(void *p, const Descriptor *d, double newval)
{
assert(d->type == DOUBLE);
double *v = pointer_to_element(p, d);
*v = newval;
}
char *get_string_element(void *p, const Descriptor *d)
{
assert(d->type == STRING);
char *v = pointer_to_element(p, d);
return v;
}
void set_string_element(void *p, const Descriptor *d, char *newval)
{
assert(d->type == STRING);
assert(d->array_dim > 1);
size_t len = strlen(newval);
if (len > d->array_dim)
len = d->array_dim - 1;
char *v = pointer_to_element(p, d);
memmove(v, newval, len);
v[len] = '\0';
}
extern void other_function(void *p);
int main(void)
{
void *sp = allocate_structure(&simulated);
if (sp != 0)
{
set_int_element(sp, &simulated.details[0], 37);
set_double_element(sp, &simulated.details[1], 3.14159);
set_string_element(sp, &simulated.details[2], "Absolute nonsense");
printf("Main (before):\n");
printf("Integer: %d\n", get_int_element(sp, &simulated.details[0]));
printf("Double: %f\n", get_double_element(sp, &simulated.details[1]));
printf("String: %s\n", get_string_element(sp, &simulated.details[2]));
other_function(sp);
printf("Main (after):\n");
printf("Integer: %d\n", get_int_element(sp, &simulated.details[0]));
printf("Double: %f\n", get_double_element(sp, &simulated.details[1]));
printf("String: %s\n", get_string_element(sp, &simulated.details[2]));
deallocate_structure(sp);
}
return 0;
}
other.c
Этот код ничего не знает о материале описания структуры в dynstruct.c
; он знает о struct simulated
, который имитирует код симуляции. Он печатает данные, которые он передал и изменяет его.
#include <stdio.h>
#include <string.h>
extern void other_function(void *p);
struct simulated
{
int number;
double value;
char string[32];
};
void other_function(void *p)
{
struct simulated *s = (struct simulated *)p;
printf("Other function:\n");
printf("Integer: %d\n", s->number);
printf("Double: %f\n", s->value);
printf("String: %s\n", s->string);
s->number *= 2;
s->value /= 2;
strcpy(s->string, "Codswallop");
}
Пример вывода
Main (before):
Integer: 37
Double: 3.141590
String: Absolute nonsense
Other function:
Integer: 37
Double: 3.141590
String: Absolute nonsense
Main (after):
Integer: 74
Double: 1.570795
String: Codswallop
Очевидно, этот код не готов к работе. Это достаточная демонстрация того, что можно сделать. Одна из проблем, с которой вам придется столкнуться, - это правильная инициализация данных Structure
и Descriptor
. Вы не можете поместить слишком много утверждений в такой код. Например, у меня действительно должно быть assert(d->size == sizeof(double);
в get_double_element()
. Также было бы разумно включить assert(d->offset % sizeof(double) == 0);
, чтобы обеспечить правильное выравнивание элемента double
. Или у вас может быть функция validate_structure(const Structure *sp);
, которая выполнила все эти проверки. Вам понадобится функция void dump_structure(FILE *fp, const char *tag, const Structure *sp);
для выгрузки определенной структуры в данный файл, перед которым стоит тег, чтобы помочь в отладке. И т.д.
Этот код является чистым C; он не компилируется компилятором C ++ как C ++. Недостаточно приведений, чтобы удовлетворить компилятор C ++.