C에서 함수 과부하를 달성 할 수있는 방법이 있습니까? 오버로드되는 간단한 함수를보고 있습니다.
foo (int a)
foo (char b)
foo (float c , int d)
나는 직접적인 방법이 없다고 생각한다. 존재하는 경우 해결 방법을 찾고 있습니다.
답변
몇 가지 가능성이 있습니다.
- printf 스타일 함수 (인수로 입력)
- opengl 스타일 함수 (함수 이름 입력)
- c ++의 c 서브 세트 (c ++ 컴파일러를 사용할 수있는 경우)
답변
예!
이 질문에 질문을 받았다 이후의 시간에, 표준 C (NO 확장)을 효과적으로있다 얻었다 의 추가로, 덕분에 (안 연산자를) 오버로드 기능을 지원 _Generic
C11의 키워드. (버전 4.9 이후 GCC에서 지원됨)
(과부하가 질문에 표시된 방식으로 진정으로 “내장 된”것은 아니지만 그렇게 작동하는 것을 구현하기는 쉽지 않습니다.)
_Generic
동일한 가족에서 컴파일시 연산자이다 sizeof
하고 _Alignof
. 표준 섹션 6.5.1.1에 설명되어 있습니다. 두 가지 주요 매개 변수, 즉 식 (런타임에 평가되지 않음)과 switch
블록 과 비슷한 형식 / 표현 연관 목록을 허용합니다 . _Generic
식의 전체 유형을 가져온 다음 “전환”하여 해당 유형의 목록에서 최종 결과 식을 선택합니다.
_Generic(1, float: 2.0,
char *: "2",
int: 2,
default: get_two_object());
위의 표현식은 다음과 같이 평가됩니다 2
.-제어 표현식의 유형은 입니다. 따라서 값 int
과 연관된 표현식을 선택합니다 int
. 이 중 아무것도 런타임에 남아 있지 않습니다. (그만큼default
절은 선택 사항입니다. 항목을 그대로두고 유형이 일치하지 않으면 컴파일 오류가 발생합니다.)
이것이 함수 오버로딩에 유용한 방법은 C 전처리기에 의해 삽입되고 제어 매크로에 전달 된 인수의 유형에 따라 결과 표현식을 선택할 수 있다는 것입니다. 따라서 (C 표준의 예) :
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
이 매크로 cbrt
는 인수 유형을 매크로에 디스패치하고 적절한 구현 함수를 선택한 다음 원래 매크로 인수를 해당 함수에 전달 하여 오버로드 된 작업을 구현합니다.
원래 예제를 구현하기 위해 다음과 같이 할 수 있습니다.
foo_int (int a)
foo_char (char b)
foo_float_int (float c , int d)
#define foo(_1, ...) _Generic((_1), \
int: foo_int, \
char: foo_char, \
float: _Generic((FIRST(__VA_ARGS__,)), \
int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A
이 경우 우리 default:
는 세 번째 경우에 연관을 사용할 수 있었지만 원리를 여러 인수로 확장하는 방법을 보여주지는 않습니다. 결과적 foo(...)
으로 인수 유형에 대해 걱정하지 않고 코드에서 사용할 수 있습니다 ([1]).
더 많은 수의 인수를 오버로드하는 함수 또는 다양한 수와 같은보다 복잡한 상황의 경우 유틸리티 매크로를 사용하여 정적 디스패치 구조를 자동으로 생성 할 수 있습니다.
void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }
#define print(...) OVERLOAD(print, (__VA_ARGS__), \
(print_ii, (int, int)), \
(print_di, (double, int)), \
(print_iii, (int, int, int)) \
)
#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"
int main(void) {
print(44, 47); // prints "int, int"
print(4.4, 47); // prints "double, int"
print(1, 2, 3); // prints "int, int, int"
print(""); // prints "unknown arguments"
}
( 여기에 구현 ) 그래서 약간의 노력으로, 당신은 과부하에 대한 네이티브 지원하는 언어처럼 꽤 많이보고 보일러의 양을 줄일 수 있습니다.
따로, C99에서 인수 의 수 (유형이 아닌)에 이미 과부하가 가능 했습니다 .
[1] C가 타입을 평가하는 방식은 당신을 넘어 뜨릴지도 모른다. 이것은 선택할 것이다 foo_int
당신이 예를 들어, 그것을 문자 그대로를 전달하려고하면, 당신은 비트에 대한 엉망이 필요 하면 지원 문자열 리터럴에 과부하를합니다. 그래도 전반적으로 꽤 시원합니다.
답변
이미 언급했듯이 C에서 지원하지 않는다는 의미에서 과부하가 발생합니다. 문제를 해결하는 일반적인 관용구는 함수에 태그 가 지정된 공용체를 허용하는 것 입니다. 이것은 struct
매개 변수에 의해 구현되는데 , 여기서 매개 변수 struct
자체는과 같은 유형 표시기 enum
및 union
다른 유형의 값으로 구성됩니다. 예:
#include <stdio.h>
typedef enum {
T_INT,
T_FLOAT,
T_CHAR,
} my_type;
typedef struct {
my_type type;
union {
int a;
float b;
char c;
} my_union;
} my_struct;
void set_overload (my_struct *whatever)
{
switch (whatever->type)
{
case T_INT:
whatever->my_union.a = 1;
break;
case T_FLOAT:
whatever->my_union.b = 2.0;
break;
case T_CHAR:
whatever->my_union.c = '3';
}
}
void printf_overload (my_struct *whatever) {
switch (whatever->type)
{
case T_INT:
printf("%d\n", whatever->my_union.a);
break;
case T_FLOAT:
printf("%f\n", whatever->my_union.b);
break;
case T_CHAR:
printf("%c\n", whatever->my_union.c);
break;
}
}
int main (int argc, char* argv[])
{
my_struct s;
s.type=T_INT;
set_overload(&s);
printf_overload(&s);
s.type=T_FLOAT;
set_overload(&s);
printf_overload(&s);
s.type=T_CHAR;
set_overload(&s);
printf_overload(&s);
}
답변
다음은 C에서 함수 오버로드를 보여주는 가장 명확하고 간결한 예입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int addi(int a, int b) {
return a + b;
}
char *adds(char *a, char *b) {
char *res = malloc(strlen(a) + strlen(b) + 1);
strcpy(res, a);
strcat(res, b);
return res;
}
#define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)
int main(void) {
int a = 1, b = 2;
printf("%d\n", add(a, b)); // 3
char *c = "hello ", *d = "world";
printf("%s\n", add(c, d)); // hello world
return 0;
}
답변
컴파일러가 gcc이고 새로운 과부하를 추가 할 때마다 수동 업데이트를 신경 쓰지 않으면 매크로 마술을하고 호출자 측면에서 원하는 결과를 얻을 수 있지만 작성하는 것이 좋지는 않지만 가능합니다 …
__builtin_types_compatible_p를보고 그것을 사용하여 비슷한 것을하는 매크로를 정의하십시오
#define foo(a) \
((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)
근데 싫은데
편집 : C1X는 다음과 같은 형식 일반 표현식을 지원합니다.
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
답변
예, 일종의
여기 예가 있습니다.
void printA(int a){
printf("Hello world from printA : %d\n",a);
}
void printB(const char *buff){
printf("Hello world from printB : %s\n",buff);
}
#define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0
#define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define _Num_ARGS_(...) __VA_ARG_N(__VA_ARGS__)
#define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1)
#define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t)
#define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args)
#define print(x , args ...) \
CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \
CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout); \
({ \
if (__builtin_types_compatible_p (typeof (x), int)) \
printA(x, ##args); \
else \
printB (x,##args); \
})
int main(int argc, char** argv) {
int a=0;
print(a);
print("hello");
return (EXIT_SUCCESS);
}
printA와 printB에서 0과 hello ..를 출력합니다.
답변
다음 접근법은 a2800276 과 유사 하지만 일부 C99 매크로 매직이 추가되었습니다.
// we need `size_t`
#include <stddef.h>
// argument types to accept
enum sum_arg_types { SUM_LONG, SUM_ULONG, SUM_DOUBLE };
// a structure to hold an argument
struct sum_arg
{
enum sum_arg_types type;
union
{
long as_long;
unsigned long as_ulong;
double as_double;
} value;
};
// determine an array's size
#define count(ARRAY) ((sizeof (ARRAY))/(sizeof *(ARRAY)))
// this is how our function will be called
#define sum(...) _sum(count(sum_args(__VA_ARGS__)), sum_args(__VA_ARGS__))
// create an array of `struct sum_arg`
#define sum_args(...) ((struct sum_arg []){ __VA_ARGS__ })
// create initializers for the arguments
#define sum_long(VALUE) { SUM_LONG, { .as_long = (VALUE) } }
#define sum_ulong(VALUE) { SUM_ULONG, { .as_ulong = (VALUE) } }
#define sum_double(VALUE) { SUM_DOUBLE, { .as_double = (VALUE) } }
// our polymorphic function
long double _sum(size_t count, struct sum_arg * args)
{
long double value = 0;
for(size_t i = 0; i < count; ++i)
{
switch(args[i].type)
{
case SUM_LONG:
value += args[i].value.as_long;
break;
case SUM_ULONG:
value += args[i].value.as_ulong;
break;
case SUM_DOUBLE:
value += args[i].value.as_double;
break;
}
}
return value;
}
// let's see if it works
#include <stdio.h>
int main()
{
unsigned long foo = -1;
long double value = sum(sum_long(42), sum_ulong(foo), sum_double(1e10));
printf("%Le\n", value);
return 0;
}