Как на чистом C передать имя типа в функцию?
Нужно передать в функцию имя типа на этапе выполнения (не компиляции!!! Макроопределение не подходят!). Как это сделать?
Нужно передать в функцию имя типа на этапе выполнения (не компиляции!!! Макроопределение не подходят!). Как это сделать?
В C
нет ни шаблонов, ни RTTI
как в C++
, или подобных механизмов, отсутствует рефлексия или интроспекция. Но есть несколько способов:
variadic arguments (va_arg(args,<type>)
)
void f(const char* fmt, ...) {
va_list args;
va_start(args,fmt);
for (const char* ptr = fmt; *ptr != '\0'; ++ptr) {
if (*ptr == 'd') {
double arg = va_arg(args,double);
}
}
va_end(args);
}
type erasure (T* -> void* -> T*
)
typedef enum { /* ... */ } Type;
typedef struct {
Type type;
void* ptr;
} Test;
void f(Test* test) {
if (test->type == TYPE) {
T* ptr = test->ptr;
ptr->implementation;
}
}
int main() {
T t;
Test test;
test.type = TYPE;
test.ptr = (void*)&t;
f(&test);
return 0;
}
union
:
#include <stdio.h>
typedef enum {
FLOAT, DOUBLE, LDOUBLE,
INT, SHORT, LONG, UINT, USHORT, ULONG
} Type;
typedef struct {
Type type;
union {
float f;
double d;
long double ld;
int si;
short ss;
long sl;
unsigned ui;
unsigned short us;
unsigned long ul;
};
} Test;
void f(Test* test) {
switch (test->type) {
case FLOAT: printf("float %f",test->f); break;
case DOUBLE: printf("double %lf",test->d); break;
case LDOUBLE: printf("long double %Lf",test->ld); break;
case INT: printf("int %d",test->si); break;
case SHORT: printf("short %hd",test->ss); break;
case LONG: printf("long %ld",test->sl); break;
case UINT: printf("unsigned int %u",test->ui); break;
case USHORT: printf("unsigned short %hu",test->us); break;
case ULONG: printf("unsigned long %lu",test->ul); break;
}
}
int main() {
Test test;
test.type = DOUBLE;
test.d = 3.14159;
f(&test);
test.type = USHORT;
test.us = (unsigned short)31459;
f(&test);
return 0;
}
В Си невозможно корректно принять внешние данные просто так, ваша программа должна знать протокол связи, структуры пакетов, и алгоритм обработки. Всё точно так-же как на передающей стороне. Иначе получится каша. Всё данные что создаются внутри программы - уже имеют известный тип, и могут быть обработаны на уровне предварительной компиляции. Можно упростить обработку, позволив компилятору самостоятельно выбирать функции обработки данных. Для этого есть макрос "_Generic((X)". Пример - https://github.com/AVI-crak/Rtos_cortex/blob/master/sPrint.h
#define dpr_(X) _Generic((X), \
const char*: soft_print_con, \
char*: soft_print, \
char: print__char, \
uint8_t: print_uint8, \
uint16_t: print_uint16, \
uint32_t: print_uint32, \
uint64_t: print_uint64, \
int8_t: print_int8, \
int16_t: print_int16, \
int32_t: print_int32, \
int64_t: print_int64, \
float: print_float, \
double: print_double, \
default: print_hex \
)(X)
Кроме того вам наверняка понадобится древний злой макрос передачи неизвестного типа данных в саму функцию "attribute((transparent_union))". Это древнее зло позволяет отправить в функцию всё что угодно без приведения типа. И если сама функция будет знать что это такое (+1 дополнительный параметр) - то внутри можно работать с данными через объединение, без ошибок и предупреждений.