Ответ 1
Невозможно динамически определить структуру, которая идентична структуре времени компиляции.
Возможно, но сложно создать динамические структуры, которые могут содержать информацию, эквивалентную структуре. Доступ к данным менее удобен, чем доступный во время компиляции.
Все остальное, вы не можете получить доступ к элементу somestruct.not_seen_at_compile_time
, используя нотацию .
или ->
, если она не была определена во время компиляции.
При использовании сетевых коммуникаций существуют другие проблемы, которые необходимо адресовать - в частности, "сущность". То есть данные на проводе, вероятно, будут включать в себя многобайтовые (2, 4, 8) целые числа, и сначала будут отправлены MSB или LSB, но если одна машина является малоконтинентальной (IA-32, IA- 64, x86/64), а другой - big-endian (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);
, чтобы выгрузить определенную структуру в указанный файл, которому предшествует тег, чтобы помочь в отладке. Etc.
Этот код является чистым C; он не компилируется компилятором С++ как С++. Недостаточно отливок для компилятора С++.