Функция посмотреть хоть какую-то структуру в C - PullRequest
2 голосов
/ 11 декабря 2019

У меня есть структура с различными типами данных. Я хочу создать универсальную функцию, которая может:

  1. просматривать любую структуру и проверять, находятся ли значения элемента в определенном диапазоне для данных типов: (EG item 1 должен быть в пределах 10 ~ 35, item 3должно быть либо 0/1). Обратите внимание, что типы и имена элементов структуры не передаются в функцию, а только структура (любая структура)
  2. Подсчитайте, сколько элементов в структуре задано любой структурой

Пример:

typedef struct _anyStruct_t
{
    uint8_t item1;
    uint16_t item2;
    bool item3;
    char item4;
}anyStruct_t

Ответы [ 3 ]

2 голосов
/ 11 декабря 2019

То, что вы запрашиваете, фактически невозможно в C.

Прежде всего, типы структур не содержат метаданных об их содержимом. Во время выполнения объект struct - это просто байт. Во время выполнения нет способа определить количество или типы членов в объекте структуры.

Во-вторых, если вы хотите сделать это для любого типа структуры, вам придется передать его адреск функции как void *, что означает, что у вас есть нет способ узнать, является ли он типом структуры вообще .

В основном вам придется создать свой собственныйТип «класс», который а) хранит метаданные о своих членах и б) поддерживает некоторую форму наследования, так что вы можете передать указатель на тип base «класс» и использовать его для доступа к метаданным и членам.

Итак, вам придется заново реализовать хороший кусок C ++.

Редактировать

На самом деле, как упоминает Эндрю ниже, даже C ++ не поддерживает отражение. Тебе придется пойти еще дальше.

0 голосов
/ 12 декабря 2019

Как уже упоминалось, нужно больше информации о том, что в struct. C, в отличие от C++, и т. Д. , не было разработано для этой абстракции. Тем не менее, это не невозможно ;ничто не мешает определить собственную виртуальную таблицу.

#include <stdlib.h> /* EXIT rand */
#include <string.h> /* strcpy */
#include <stdio.h>  /* sprintf, printf */
#include <assert.h> /* assert */
#include <stdint.h> /* (C99) uint8_t uint16_t */
#include <stdbool.h> /* (C99) bool */

union AllTypes {
    bool boolean;
    char letter;
    uint8_t byte;
    uint16_t word;
};

/* `is_valid` functions. */

static bool is_valid_boolean(const union AllTypes all) {
    /* Not sure this will ever be false. */
    return all.boolean == true || all.boolean == false;
}

static bool is_valid_letter(const union AllTypes all) {
    return (all.letter >= 'a' && all.letter <= 'z')
        || (all.letter >= 'A' && all.letter <= 'Z');
}

static bool is_valid_byte(const union AllTypes all) {
    return all.byte <= 35 && all.byte >= 10;
}

static bool is_valid_word(const union AllTypes all) {
    return all.word < 1000;
}

/* `to_string` functions */

static void boolean_to_string(const union AllTypes all, char (*const a)[12]) {
    strcpy(*a, all.boolean ? "true" : "false");
}

static void letter_to_string(const union AllTypes all, char (*const a)[12]) {
    sprintf(*a, "'%c'", all.letter);
}

static void byte_to_string(const union AllTypes all, char (*const a)[12]) {
    sprintf(*a, "b%u", all.byte);
}

static void word_to_string(const union AllTypes all, char (*const a)[12]) {
    sprintf(*a, "w%u", all.word);
}

typedef void (*ToString)(const union AllTypes all, char (*const a)[12]);

/* The virtual-table. */

static const struct VTable {
    ToString to_string;
    bool (*is_valid)(const union AllTypes);
} vt_boolean = { &boolean_to_string, &is_valid_boolean },
    vt_letter = { &letter_to_string, &is_valid_letter },
    vt_byte = { &byte_to_string, &is_valid_byte },
    vt_word = { &word_to_string, &is_valid_word };

/* The data has an extra `vt`; this would be implicit in C++. */

struct Data {
    const struct VTable *vt;
    union AllTypes all;
};

static void to_string(const struct Data *const data, char (*const a)[12]) {
    data->vt->to_string(data->all, a);
}

static bool is_valid(const struct Data *const data) {
    return data->vt->is_valid(data->all);
}

/* Testing. */

static void fill(struct Data *const data) {
    assert(data);
    switch(rand() / (RAND_MAX / 4 + 1)) {
    case 0: data->vt = &vt_boolean;
        data->all.boolean = rand() / (RAND_MAX / 2); break;
    case 1: data->vt = &vt_letter;
        data->all.letter = rand() / (RAND_MAX / 26 + 1) + 'a'; break;
    case 2: data->vt = &vt_byte;
        data->all.byte = rand() / (RAND_MAX / 25 + 1) + 10; break;
    case 3: data->vt = &vt_word;
        data->all.word = rand() / (RAND_MAX / 999 + 1); break;
    }
}

int main(void) {
    struct Data data[32], *d, *const d_end = data + sizeof data / sizeof *data;
    char a[12];
    /* Fill the data with random values. */
    for(d = data; d < d_end; d++) {
        fill(d);
        if(!is_valid(d)) return fprintf(stderr, "Impossible!\n"), assert(0),
            EXIT_FAILURE;
    }
    /* Print. */
    fputs("{ ", stdout);
    for(d = data; d < d_end; d++) {
        if(d != data) fputs(", ", stdout);
        to_string(d, &a);
        fputs(a, stdout);
    }
    fputs(" }.\n", stdout);
    return EXIT_SUCCESS;
}

Распечатывает на моей машине

{false, w458, b15, true, b33, 'n',w34, правда, b10, 'b', 'r', b33, w526, правда, 's', w761, 'b', b18, b28, w364, правда, b28, b11, b32, 'l', w477,false, 'e', ​​'x', w60, w504, b17}.

0 голосов
/ 11 декабря 2019

просмотреть любую структуру и проверить, находятся ли значения элемента в определенном диапазоне для данных типов: (Элемент 1 EG должен быть в пределах 10 ~ 35, элемент 3 должен быть либо 0/1). Обратите внимание, что типы и имена элементов структуры не передаются в функцию, просто структура (любая структура)

Это невозможно в C. Если у вас есть только указатель на неизвестную структуру, то естьнет способа узнать, какие поля имеет структура.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...