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자체는과 같은 유형 표시기 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); 
}

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.