Как на чистом C передать имя типа в функцию?
Нужно передать в функцию имя типа на этапе выполнения (не компиляции!!! Макроопределение не подходят!). Как это сделать?
Ответы (2 шт):
В 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 дополнительный параметр) - то внутри можно работать с данными через объединение, без ошибок и предупреждений.