Найти в Дзене

Создание функции с типом данных как параметром в Си

Для начала следует сказать, что создать функцию, которая принимала бы как параметр тип данных в си невозможно. Однако можно создать макрос, который работал бы похожим образом. Изначально передо мной стояла задача вывести диапазоны типов данных (вообще для этого есть специальная библиотека). Но мне было интересно реализовать это самостоятельно. Конечно, можно было бы просто прописать это вручную, но я решил посмотреть, получится ли сократить этот код (не получилось). Итак, для начала создадим структуру с одним полем, что положить туда размер типа данных: struct type_property { short size; }; После этого создадим массив структур type_property в котором для каждого элемента будет вызываться макрос, который, в свою очередь, будет брать как параметр тип данных и возвращать его размер: struct type_property properties[] = { TYPE_PROPERTY_INIT(int), TYPE_PROPERTY_INIT(float), TYPE_PROPERTY_INIT(double), TYPE_PROPERTY_INIT(char), TYPE_PROPERTY_INIT(long long), TYPE_P

Для начала следует сказать, что создать функцию, которая принимала бы как параметр тип данных в си невозможно. Однако можно создать макрос, который работал бы похожим образом.

Изначально передо мной стояла задача вывести диапазоны типов данных (вообще для этого есть специальная библиотека). Но мне было интересно реализовать это самостоятельно. Конечно, можно было бы просто прописать это вручную, но я решил посмотреть, получится ли сократить этот код (не получилось).

Итак, для начала создадим структуру с одним полем, что положить туда размер типа данных:

struct type_property {
short size;
};

После этого создадим массив структур type_property в котором для каждого элемента будет вызываться макрос, который, в свою очередь, будет брать как параметр тип данных и возвращать его размер:

struct type_property properties[] = {
TYPE_PROPERTY_INIT(int),
TYPE_PROPERTY_INIT(float),
TYPE_PROPERTY_INIT(double),
TYPE_PROPERTY_INIT(char),
TYPE_PROPERTY_INIT(long long),
TYPE_PROPERTY_INIT(unsigned),
TYPE_PROPERTY_INIT(short),
TYPE_PROPERTY_INIT(unsigned char),
TYPE_PROPERTY_INIT(unsigned int),
};

Теперь определим сам макрос (напомню, что макросы определяются через директиву препроцессора #define):

#define TYPE_PROPERTY_INIT(type) {
sizeof(type)
}

Получилось достаточно громоздко, но на данном этапе меня интересовала уже на возможность сократить код, а возможность подобной реализации в принципе. Так как данные хранятся в массиве структур (из-за того, что невозможно в обычном массиве хранить возвращаемое значение вызываемой внутри функции), где каждое поле - это отдельный тип данных, то для корректного вывода информации пользователю я воспользовался двухмерными массивами из символов (где первый индекс отвечает за количество символов в слове, а второй за количество слов), куда в том же порядке, что и в properties записал названия типов данных:

char t_names[][15] = { "int", "float", "double", "char", "long long", "unsigned", "short", "unsigned char", "unsigned int" };

Далее создал две функции, которые выводят диапазон значений для знакового (t_range) и беззнакового типов данных (ut_range):

{
return (powl(2, (s_type * 8) - 1) - 10);
}
unsigned long long ut_range(short s_type)
{
return (powl(2, s_type * 8) - 1);
}

В функции main создал цикл от 0 до количества типов данных в массиве (размер массива поделить на размер размер одного элемента (t_names_size). Далее в самом цикле текущее значение размера типа данных присваивалось переменной s_type. Тут стоит упомянуть, что так как размеры типов данных в properties расположены в том же порядке, в котором идут названия этих типов данных в t_names, то и для того и для другого будет одинаковый индекс в цикле. После этого создал условие в котором проверяется вхождение подстроки "unsigned" в текущий элемент списка (если тип unsigned, то он начинается с нуля и его положительный максимум в два раза больше обычного, именно поэтому для расчета использовалось две функции).

int main()
{
short s_type;
unsigned long long range;
short t_names_size = sizeof(t_names) / sizeof(t_names[0]);
for (int i = 0; i < t_names_size; i++)
{
s_type = properties[i].size;
if (strstr(t_names[i], "unsigned"))
{
range = ut_range(s_type);
printf("Size of %s - %d, range from 0 to %llu\n", t_names[i], s_type, range);
}
else
{
range = t_range(s_type);
printf("Size of %s - %d, range from -%llu to %llu\n", t_names[i], s_type, range - 1, range);
}
}
}

На этом все. Буду рад критике, советам энтузиастов, которые смогу упростить этот код и людям, которые найдут ошибки.