В коде, который я пишу, мне нужны функции foo(int, char*)
и foo(int, int)
.
Если бы я кодировал это в С++, я бы использовал шаблоны. Существует ли какой-либо эквивалент для C? Или я должен использовать указатели void? Как?
В коде, который я пишу, мне нужны функции foo(int, char*)
и foo(int, int)
.
Если бы я кодировал это в С++, я бы использовал шаблоны. Существует ли какой-либо эквивалент для C? Или я должен использовать указатели void? Как?
Вы не можете этого сделать.
В C нет перегрузок, одной функции, одного имени, вам нужно будет использовать тип, который поддерживает все ваши потребности, например. (void *)
Либо это, либо сделать foo_int(int,int)
и a foo_char(int, char*)
Я думаю, что самое близкое, что вы можете получить в шаблонах C к шаблонам, - это какой-то уродливый макрокод. Например, чтобы определить простую функцию, которая возвращает дважды свой аргумент:
#define MAKE_DOUBLER(T) \
T doubler_##T(T x) { \
return 2 * x; \
}
MAKE_DOUBLER(int)
MAKE_DOUBLER(float)
Обратите внимание, что поскольку C не имеет перегрузки функций, вам нужно сыграть трюки с именем функции (вышесказанное делает как doubler_int
, так и doubler_float
, и вам придется их так называть).
printf("%d\n", doubler_int(5));
printf("%f\n", doubler_float(12.3));
Да, есть. Вы можете использовать типовое выражение в C11:
#include <stdio.h>
void foo_char_ptr(int a, char *b) {
printf("Called int, char*.\n");
}
void foo_int(int a, int b) {
printf("Called int, int.\n");
}
#define foo(a, b) _Generic((b), char*: foo_char_ptr, int: foo_int)(a, b)
int main() {
foo(1, 1);
foo(1, "foo");
}
// Output:
// Called int, int.
// Called int, char*.
Другие обсудили внутреннее ограничение c в отношении перегрузки. Обратите внимание, однако, что если вы можете вывести, какой случай нужен, вы можете использовать varargs:
#include <stdarg.h>
foo(int, ...);
Если вы не можете его вывести, вы можете передать дополнительный аргумент:
foo(int, char *spec, ...);
где spec
сообщает функции, что ожидать в последующих аргументах. Подобно семействам функций printf
и scanf
. На самом деле вам может показаться удобным повторное использование соглашений printf/scanf для указания типа, таким образом, чтобы ваши пользователи не могли наклонить другой мини-язык.
Вместо void * вы также можете использовать объединение для хранения любых типов данных, которые вам нужны:
typedef struct {
int type;
union {
char* char_ptr;
int int_val;
// etc...
};
} foo_data;
void foo(foo_data data)
{
switch (data.type) {
case 0:
printf("%s\n", data.char_ptr);
break;
case 1:
printf("%i\n", data.int_val);
break;
}
}
void main()
{
foo_data data;
data.type = 0; data.char_ptr = "hello";
foo(data);
data.type = 1; data.int_val = 12;
foo(data);
}
Конечно, вы должны создать константы для значений типа.
Шаблоны могут быть реализованы с использованием заголовков шаблонов.
Пусть foo.h вот так:
#ifndef PREFIX
#define PREFIX
#endif
#define CCAT2(x, y) x ## y
#define CCAT(x, y) CCAT2(x, y)
#define FN(x) CCAT(PREFIX, x)
#ifndef T
#error Template argument missing.
#endif
void FN(foo)(int x, T t)
{
// Whatever.
}
#undef T
#undef PREFIX
#undef CCAT2
#undef CCAT
#undef FN
Чтобы использовать его, вы можете:
#define T char*
#define PREFIX pchar_
#include "foo.h"
#define T int
#define PREFIX int_
#include "foo.h"
Теперь у вас есть pchar_foo()
и int_foo()
, которые вы можете использовать.
Преимущества этого в том, что если есть проблема с сборкой, вы получаете номер строки в заголовке шаблона вместо компилятора, просто говоря, что макрос ошибочен, а также завершение кода в некоторых IDE.
Макросы PREFIX
, CCAT
и FN
очень распространены, поэтому я выделил их определение в отдельный заголовок, а их неопределенность на другой.
Я реализовал части STL, используя этот шаблон для удовольствия и использую его в некоторых моих проектах C.
Вы можете использовать _Generic
от GCC. (Хотя это НЕ переносимо на другие компиляторы) http://www.robertgamble.net/2012/01/c11-generic-selections.html