Как уже упоминалось, нужно больше информации о том, что в 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}.