C에서 함수 과부하를 달성하는 방법은 무엇입니까?


240

C에서 함수 과부하를 달성 할 수있는 방법이 있습니까? 오버로드되는 간단한 함수를보고 있습니다.

foo (int a)  
foo (char b)  
foo (float c , int d)

나는 직접적인 방법이 없다고 생각한다. 존재하는 경우 해결 방법을 찾고 있습니다.


6
왜 이렇게 하시겠습니까? C는 다형성 능력이 없습니다. 따라서 foo (random type)는 불가능합니다. 그냥 등 실제 funcs의 foo_i, foo_ch, foo_d 만들
jmucchiello

4
void 포인터와 타입 ID를 사용하여 나쁜 길을 갈 수 있습니다.
alk

11
나는이 질문에 대한 답변 새로운 C 표준 으로 원래 요청 된 이후로 바뀌 었다는 사실에 주목해야한다고 생각한다 .
Leushenko

답변:


127

몇 가지 가능성이 있습니다.

  1. printf 스타일 함수 (인수로 입력)
  2. opengl 스타일 함수 (함수 이름 입력)
  3. c ++의 c 서브 세트 (c ++ 컴파일러를 사용할 수있는 경우)

1
OpenGL 스타일 함수에 대한 링크를 설명하거나 제공 할 수 있습니까?
FL4SOF 2019 년

1
@Lazer은 : 여기에 하나 간단한 printf와 같은 기능 구현.
Alexey Frunze

12
아니요. printf는 기능 과부하가 아닙니다. 그것은 vararg를 사용합니다! 그리고 C는 함수 오버로딩을 지원하지 않습니다.
hqt

52
@hqt 대답은 단어 오버로딩을 언급하지 않습니다.
kyrias 2016 년

1
@kyrias 대답이 과부하에 관한 것이 아니라면 그것은 잘못된 질문에 있습니다
Michael Mrozek

233

예!

이 질문에 질문을 받았다 이후의 시간에, 표준 C (NO 확장)을 효과적으로있다 얻었다 의 추가로, 덕분에 (안 연산자를) 오버로드 기능을 지원 _GenericC11의 키워드. (버전 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당신이 예를 들어, 그것을 문자 그대로를 전달하려고하면, 당신은 비트에 대한 엉망이 필요 하면 지원 문자열 리터럴에 과부하를합니다. 그래도 전반적으로 꽤 시원합니다.


귀하의 예에 따르면 과부하 된 유일한 것은 매크로와 같은 기능 인 것 같습니다. 내가 올바르게 이해하고 있는지 보자. 함수를 오버로드하려면 전처리기를 사용하여 전달 된 데이터 유형에 따라 함수 호출을 우회하는 것입니까?
Nick

아아, C11이 붙잡을 때마다 MISRA가 변수 인수 목록을 금지하는 것과 같은 이유로이 기능을 채택하지 않을 것이라고 가정합니다. 나는 세상에서 MISRA에 아주 가까이 붙어 있습니다.
Nick

9
@Nick는 모든 오버로드입니다. 다른 언어에서는 암시 적으로 처리됩니다 (예 : 과부하는 여러 본문을 의미하므로 실제로 어떤 언어로든 "오버로드 된 함수에 대한 포인터"를 얻을 수 없음). 이것은 전 처리기만으로는 할 수 없으며 어떤 종류의 디스패치가 필요합니다. 전처리 기는 모양을 바꿉니다.
Leushenko

1
C99에 대해 잘 알고 있고이를 수행하는 방법을 배우고 자하는 누군가 C에게는 매우 복잡해 보입니다.
Tyler Crompton

5
@TylerCrompton 컴파일 타임에 평가됩니다.
JAB

75

이미 언급했듯이 C에서 지원하지 않는다는 의미에서 과부하가 발생합니다. 문제를 해결하는 일반적인 관용구는 함수에 태그지정된 공용체를 허용하는 것 입니다. 이것은 struct매개 변수에 의해 구현되는데 , 여기서 매개 변수 struct자체는과 같은 유형 표시기 enumunion다른 유형의 값으로 구성됩니다. 예:

#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); 
}

22
당신은 모든하지 왜 whatever(별도의 함수로들 set_int, set_float등). 그런 다음 "타입으로 태그 지정"은 "타입 이름을 함수 이름에 추가"가됩니다. 이 답변의 버전은 더 입력, 더 런타임 비용, 컴파일 시간에 잡힐되지 않습니다 오류의 더 기회 ... 나는보고 실패 포함 전혀 이점을 이런 식으로 일을에를! 16 upvotes ?!
Ben

20
벤,이 답변은 단지“그렇게하지 마라”라는 말 대신 질문에 대답 하기 때문에 상향 조정되었습니다 . C에서 별도의 함수를 사용하는 것이 관용적 인 것이 맞지만 C에서 다형성을 원한다면 이것이 좋은 방법입니다. 또한이 답변은 컴파일러 또는 VM에서 런타임 다형성을 구현하는 방법을 보여줍니다. 유형에 값을 태그 한 다음 그에 따라 디스패치합니다. 따라서 원래 질문에 대한 훌륭한 답변입니다.
닐스 폰 바스

20

다음은 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;
}

https://gist.github.com/barosl/e0af4a92b2b8cabd05a7


1
나는 이것이 정신적 으로 stackoverflow.com/a/25026358/1240268 의 속임수라고 생각합니다 (그러나 설명은 적음).
Andy Hayden

1
나는 확실히 # 1240268 인 슬라이싱 및 다이 싱 찹에 완전하고 실행 가능한 코드의 단일 연속 블록을 선호합니다. 각자 자신에게.
Jay Taylor

1
나는 그들이하는 일과 왜 일하는지 설명하는 답변을 선호합니다. 이것도 마찬가지입니다. "아직 본 것 중에 가장 좋은 것"은 설명이 아닙니다.
underscore_d

19

컴파일러가 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)

13

예, 일종의

여기 예가 있습니다.

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 ..를 출력합니다.


2
int main (int argc, char ** argv) {int a = 0; 인쇄 (a); print ( "hello"); 반환 (EXIT_SUCCESS); printA 및 printB에서}가 출력 0 안녕하세요 .. ...
경감 Barbossa

1
__builtin_types_compatible_p, GCC 컴파일러가 구체적이지 않습니까?
Sogartar

11

다음 접근법은 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;
}

11

이것은 전혀 도움이되지는 않지만 clang을 사용하는 경우 overloadable 속성을 사용할 수 있습니다-C로 컴파일 할 때도 작동합니다

http://clang.llvm.org/docs/AttributeReference.html#overloadable

헤더

extern void DecodeImageNow(CGImageRef image, CGContextRef usingContext) __attribute__((overloadable));
extern void DecodeImageNow(CGImageRef image) __attribute__((overloadable));

이행

void __attribute__((overloadable)) DecodeImageNow(CGImageRef image, CGContextRef usingContext { ... }
void __attribute__((overloadable)) DecodeImageNow(CGImageRef image) { ... }

10

그런 의미에서 당신은 할 수 없습니다.

당신은 va_arg같은 함수 를 선언 할 수 있습니다

void my_func(char* format, ...);

하지만 첫 번째 인수에서 변수 수와 변수 유형에 대한 정보를 전달해야합니다 printf().


6

일반적으로 유형에 이름이 추가되거나 추가됨을 나타내는 사마귀. 매크로를 사용하여 벗어날 수는 있지만 일부는 시도하려는 작업에 따라 다릅니다. C에는 다형성이 없으며 강제력 만 있습니다.

매크로를 사용하여 간단한 일반 작업을 수행 할 수 있습니다.

#define max(x,y) ((x)>(y)?(x):(y))

컴파일러가 typeof를 지원 하면 매크로에 더 복잡한 연산을 넣을 수 있습니다. 그런 다음 foo (x) 기호를 사용하여 서로 다른 유형의 동일한 작업을 지원할 수 있지만 서로 다른 오버로드간에 동작을 변경할 수는 없습니다. 매크로 대신 실제 기능을 원한다면 유형에 이름을 붙여 넣고 두 번째 붙여 넣기를 사용하여 액세스 할 수 있습니다 (시도하지 않았습니다).


매크로 기반 접근 방식에 대해 조금 더 설명 할 수 있습니다.
FL4SOF

4

Leushenko의 대답 은 정말 멋진 입니다.이 foo예제는 GCC로 컴파일하지 않습니다 .GCC에서 실패 foo(7)하고 FIRST매크로와 실제 함수 호출 ( (_1, __VA_ARGS__), 잉여 쉼표로 남음). 추가 과부하를 제공하려는 경우 문제가 발생합니다 와 같은foo(double) .

그래서 void overload를 허용하는 것을 포함하여 답변을 조금 더 자세히 설명하기로 결정했습니다.foo(void) 이는 상당히 문제가되었습니다 ...).

아이디어는 다음과 같습니다. 다른 매크로에서 둘 이상의 제네릭을 정의하고 인수 수에 따라 올바른 것을 선택하십시오!

이 답변을 바탕으로 인수의 수는 매우 쉽습니다 .

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

그것은 좋으며, 우리는 SELECT_1또는 SELECT_2(또는 당신이 원하거나 필요로하는 경우 더 많은 인수)로 해결하므로 적절한 정의가 필요합니다.

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1),    \
        int: foo_int,                   \
        char: foo_char,                 \
        double: foo_double              \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

좋아, 나는 이미 void 오버로드를 추가했다. 그러나 이것은 실제로 빈 표준 변수를 허용하지 않는 C 표준에 의해 다루어지지 않는다. 즉 우리 는 컴파일러 확장에 의존한다. !

처음에 빈 매크로 호출 ( foo())은 여전히 ​​토큰을 생성하지만 빈 토큰을 생성합니다. 따라서 계산 매크로는 빈 매크로 호출에서도 실제로 0 대신 1을 반환합니다. 목록이 비어 있는지 여부에 따라 __VA_ARGS__ 조건부 뒤에 쉼표를 배치하면이 문제를 "쉽게"제거 할 수 있습니다 .

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

보였다 쉽게,하지만 COMMA매크로는 상당히 무거운이다; 다행 스럽게도이 주제는 Jens Gustedt (감사, Jens) 의 블로그 에서 이미 다룹니다 . 기본 요령은 함수 매크로가 괄호로 묶이지 않으면 확장되지 않는다는 것입니다. 자세한 설명은 Jens의 블로그를 살펴보십시오 ... 우리는 필요에 따라 매크로를 약간 수정해야합니다 (짧은 이름을 사용하겠습니다) 간결한 주장은 적습니다).

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, _3, N, ...) N
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
// ... (all others with comma)
#define COMMA_1111 ,

그리고 지금 우리는 괜찮습니다 ...

한 블록의 완전한 코드 :

/*
 * demo.c
 *
 *  Created on: 2017-09-14
 *      Author: sboehler
 */

#include <stdio.h>

void foo_void(void)
{
    puts("void");
}
void foo_int(int c)
{
    printf("int: %d\n", c);
}
void foo_char(char c)
{
    printf("char: %c\n", c);
}
void foo_double(double c)
{
    printf("double: %.2f\n", c);
}
void foo_double_int(double c, int d)
{
    printf("double: %.2f, int: %d\n", c, d);
}

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
        int: foo_int,                \
        char: foo_char,              \
        double: foo_double           \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, N, ...) N

#define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0)
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 ,

int main(int argc, char** argv)
{
    foo();
    foo(7);
    foo(10.12);
    foo(12.10, 7);
    foo((char)'s');

    return 0;
}

1

C ++ 만 사용 하고이 기능을 제외한 다른 모든 C ++ 기능을 사용할 수는 없습니까?

여전히 엄격한 C가 없다면 대신 가변 함수 를 권장 합니다 .


3
코딩하려는 OS에서 C ++ 컴파일러를 사용할 수 없으면 아닙니다.
Brian

2
뿐만 아니라 이름이 엉망이 아닌 C ABI를 원할 수도 있습니다.
Spudd86


-4

아래 코드가 함수 오버로드를 이해하는 데 도움이되기를 바랍니다.

#include <stdio.h>
#include<stdarg.h>

int fun(int a, ...);
int main(int argc, char *argv[]){
   fun(1,10);
   fun(2,"cquestionbank");
   return 0;
}
int fun(int a, ...){
  va_list vl;
  va_start(vl,a);

  if(a==1)
      printf("%d",va_arg(vl,int));
   else
      printf("\n%s",va_arg(vl,char *));
}

2
답은 무엇을하고 있고 왜 작동하는지 설명해야합니다. 그렇지 않다면 어떻게 다른 사람이 무엇을 이해하도록 도울 수 있습니까?
underscore_d

여기에는 과부하가 없습니다.
melpomene

va_end 님이 호출되지 않았습니다
user2262111
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.