문제

C에서 함수에 기본 인수를 지정하는 방법이 있습니까?

도움이 되었습니까?

해결책

설마. 유일한 방법은 varargs 기능을 작성하십시오 발신자가 통과하지 않은 인수에 대한 기본값을 수동으로 채 웁니다.

다른 팁

와, 여기 사람들은 다들 너무 비관주의자예요.대답은 '예'입니다.

그것은 사소한 것이 아닙니다:결국, 우리는 코어 함수,지지 구조, 래퍼 함수 및 래퍼 함수 주변의 매크로를 가질 수 있습니다.내 작업에는 이 모든 것을 자동화하는 매크로 세트가 있습니다.흐름을 이해하면 쉽게 수행하기가 쉽습니다.

나는 이것을 다른 곳에 썼으므로 여기에 요약을 보완하기 위한 자세한 외부 링크가 있습니다: http://modelingwithdata.org/arch/00000022.htm

우리는 방향을 바꾸고 싶습니다

double f(int i, double x)

기본값(i=8, x=3.14)을 사용하는 함수로 변환합니다.컴패니언 구조체를 정의합니다.

typedef struct {
    int i;
    double x;
} f_args;

함수 이름 바꾸기 f_base, 기본값을 설정하고 기본을 호출하는 래퍼 함수를 ​​정의합니다.

double var_f(f_args in){
    int i_out = in.i ? in.i : 8;
    double x_out = in.x ? in.x : 3.14;
    return f_base(i_out, x_out);
}

이제 C의 가변 매크로를 사용하여 매크로를 추가합니다.이런 식으로 사용자는 자신이 실제로 채우고 있다는 것을 알 필요가 없습니다. f_args 구조를 만들고 그들이 평소대로 하고 있다고 생각합니다.

#define f(...) var_f((f_args){__VA_ARGS__});

좋습니다. 이제 다음이 모두 작동합니다.

f(3, 8);      //i=3, x=8
f(.i=1, 2.3); //i=1, x=2.3
f(2);         //i=2, x=3.14
f(.x=9.2);    //i=8, x=9.2

복합 이니셜라이저가 정확한 규칙에 대한 기본값을 설정하는 방법에 대한 규칙을 확인하세요.

작동하지 않는 한 가지: f(0), 우리는 결 측값과 0을 구별 할 수 없기 때문입니다.내 경험에 따르면, 이것은 조심해야 할 것이지만, 필요에 따라 돌볼 수 있습니다.-기본값이 실제로 0 인 시간의 절반.

나는 인기와 불이행이라는 이름의 인수와 기본값이 실제로 C로 코딩을 더 쉽고 재미있게 만들어 내기 때문에 이것을 작성하는 데 어려움을 겪었습니다.그리고 C는 너무 단순하고 여전히이 모든 것을 가능하게하기에 충분한 것이있어서 훌륭합니다.

예. :-) 그러나 당신이 기대할 수있는 방식은 아닙니다.

int f1(int arg1, double arg2, char* name, char *opt);

int f2(int arg1, double arg2, char* name)
{
  return f1(arg1, arg2, name, "Some option");
}

불행히도 C는 메소드를 과부하 할 수 없으므로 두 가지 다른 기능으로 끝납니다. 그럼에도 불구하고 F2를 호출하면 실제로 기본값으로 F1을 호출 할 것입니다. 이것은 "반복하지 말아라"솔루션으로, 기존 코드를 복사/붙여 넣지 않도록 도와줍니다.

기본값에 이름이 지정된 매개 변수 (만)를 사용하는 함수를 만들 수 있습니다. 이것은 Bk.의 답변의 연속입니다.

#include <stdio.h>                                                               

struct range { int from; int to; int step; };
#define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__})   

/* use parentheses to avoid macro subst */             
void (range)(struct range r) {                                                     
    for (int i = r.from; i <= r.to; i += r.step)                                 
        printf("%d ", i);                                                        
    puts("");                                                                    
}                                                                                

int main() {                                                                     
    range();                                                                    
    range(.from=2, .to=4);                                                      
    range(.step=2);                                                             
}    

C99 표준은 초기화에서 나중에 이름이 이전 항목을 무시한다고 정의합니다. 또한 표준 위치 매개 변수도 가질 수 있으며 그에 따라 매크로 및 기능 서명을 변경합니다. 기본값 매개 변수는 이름이 지정된 매개 변수 스타일로만 사용할 수 있습니다.

프로그램 출력 :

1 2 3 4 5 6 7 8 9 10 
2 3 4 
1 3 5 7 9

Opencv 다음과 같은 것을 사용합니다.

/* in the header file */

#ifdef __cplusplus
    /* in case the compiler is a C++ compiler */
    #define DEFAULT_VALUE(value) = value
#else
    /* otherwise, C compiler, do nothing */
    #define DEFAULT_VALUE(value)
#endif

void window_set_size(unsigned int width  DEFAULT_VALUE(640),
                     unsigned int height DEFAULT_VALUE(400));

사용자가 자신이 무엇을 써야하는지 모르는 경우이 트릭은 도움이 될 수 있습니다.

usage example

아니.

최신 C99 표준조차도이를 지원하지 않습니다.

아니요, C ++ 언어 기능입니다.

아마도이 작업을 수행하는 가장 좋은 방법 (상황에 따라 귀하의 경우 가능하거나 그렇지 않을 수도 있음)는 C ++로 이동하여 '더 나은 C'로 사용하는 것입니다. 클래스, 템플릿, 연산자 과부하 또는 기타 고급 기능을 사용하지 않고 C ++를 사용할 수 있습니다.

이렇게하면 기능 오버로드 및 기본 매개 변수 (및 다른 기능을 사용하기로 선택한 다른 기능)가있는 C의 변형이 제공됩니다. C ++의 제한된 하위 집합 만 사용하는 것에 대해 진지하게 생각한다면 약간의 훈련을 받아야합니다.

많은 사람들이 이런 식으로 C ++를 사용하는 것이 끔찍한 아이디어라고 말하며, 요점이있을 수 있습니다. 그러나 그것은 단지 의견 일뿐입니다. C ++의 기능을 사용하는 것이 유효하다고 생각합니다. C ++의 성공 이유의 중요한 부분은 정확히 초기에 이런 식으로 많은 프로그래머가 사용했기 때문이라고 생각합니다.

짧은 대답: 아니.

약간 더 긴 답변 : 오래된 것이 있습니다. 낡은 당신이 당신의 문자열을 전달하는 해결 방법 구문 분석 선택적 인수 :

int f(int arg1, double arg2, char* name, char *opt);

Opt는 "name = value"쌍 또는 무언가를 포함 할 수 있고 원하는 곳에

n = f(2,3.0,"foo","plot=yes save=no");

분명히 이것은 때때로 유용합니다. 일반적으로 기능 제품군에 대한 단일 인터페이스를 원할 때.


C ++의 전문 프로그램에 의해 작성된 입자 물리 코드 에서이 접근법이 여전히 발견됩니다 (예 : 뿌리). 주요 장점은 다시 호환성을 유지하면서 거의 무기한으로 확장 될 수 있다는 것입니다.

또 다른 옵션이 사용됩니다 struct에스:

struct func_opts {
  int    arg1;
  char * arg2;
  int    arg3;
};

void func(int arg, struct func_opts *opts)
{
    int arg1 = 0, arg3 = 0;
    char *arg2 = "Default";
    if(opts)
      {
        if(opts->arg1)
            arg1 = opts->arg1;
        if(opts->arg2)
            arg2 = opts->arg2;
        if(opts->arg3)
            arg3 = opts->arg3;
      }
    // do stuff
}

// call with defaults
func(3, NULL);

// also call with defaults
struct func_opts opts = {0};
func(3, &opts);

// set some arguments
opts.arg3 = 3;
opts.arg2 = "Yes";
func(3, &opts);

아니.

아니요, 그러나 당신은 a를 사용하는 것을 고려할 수 있습니다 세트 기본 args를 사용하여 근사화하기위한 함수 (또는 매크로)의 :

// No default args
int foo3(int a, int b, int c)
{
    return ...;
}

// Default 3rd arg
int foo2(int a, int b)
{
    return foo3(a, b, 0);  // default c
}

// Default 2nd and 3rd args
int foo1(int a)
{
    return foo3(a, 1, 0);  // default b and c
}

예, C99의 기능을 사용하면이 작업을 수행 할 수 있습니다. 이것은 새로운 데이터 구조를 정의하지 않고 작동하지 않고 런타임에 호출 된 방법을 결정하고 계산 오버 헤드없이 작동하지 않습니다.

자세한 설명은 내 게시물을 참조하십시오

http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/

젠스

일반적으로 아니요, 그러나 GCC에서는 매크로를 사용하여 Funca ()의 마지막 매개 변수를 선택할 수 있습니다.

funcb ()에서는 'b'매개 변수의 기본값이 필요하다는 특수 값 (-1)을 사용합니다.

#include <stdio.h> 

int funcA( int a, int b, ... ){ return a+b; }
#define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 ) 


int funcB( int a, int b ){
  if( b == -1 ) b = 8;
  return a+b;
}

int main(void){
  printf("funcA(1,2): %i\n", funcA(1,2) );
  printf("funcA(1):   %i\n", funcA(1)   );

  printf("funcB(1, 2): %i\n", funcB(1, 2) );
  printf("funcB(1,-1): %i\n", funcB(1,-1) );
}

나는 Jens Gustedt 's를 개선했습니다 대답 하도록 하다:

  1. 인라인 기능은 사용되지 않습니다
  2. 기본값은 전처리 중에 계산됩니다
  3. 모듈 식 재사용 매크로
  4. 허용 기본값에 대한 불충분 한 인수의 경우를 의미있게 일치시키는 컴파일러 오류를 설정할 수 있습니다.
  5. 인수 유형이 모호하지 않은 상태로 유지되는 경우 기본값은 매개 변수 목록의 꼬리를 형성 할 필요가 없습니다.
  6. C11 _generic과 인터 로프합니다
  7. 인수 횟수만큼 기능 이름을 변경하십시오!

variadic.h :

#ifndef VARIADIC

#define _NARG2(_0, _1, _2, ...) _2
#define NUMARG2(...) _NARG2(__VA_ARGS__, 2, 1, 0)
#define _NARG3(_0, _1, _2, _3, ...) _3
#define NUMARG3(...) _NARG3(__VA_ARGS__, 3, 2, 1, 0)
#define _NARG4(_0, _1, _2, _3, _4, ...) _4
#define NUMARG4(...) _NARG4(__VA_ARGS__, 4, 3, 2, 1, 0)
#define _NARG5(_0, _1, _2, _3, _4, _5, ...) _5
#define NUMARG5(...) _NARG5(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define _NARG6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define NUMARG6(...) _NARG6(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define _NARG7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
#define NUMARG7(...) _NARG7(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define NUMARG8(...) _NARG8(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define NUMARG9(...) _NARG9(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __VARIADIC(name, num_args, ...) name ## _ ## num_args (__VA_ARGS__)
#define _VARIADIC(name, num_args, ...) name (__VARIADIC(name, num_args, __VA_ARGS__))
#define VARIADIC(name, num_args, ...) _VARIADIC(name, num_args, __VA_ARGS__)
#define VARIADIC2(name, num_args, ...) __VARIADIC(name, num_args, __VA_ARGS__)

// Vary function name by number of arguments supplied
#define VARIADIC_NAME(name, num_args) name ## _ ## num_args ## _name ()
#define NVARIADIC(name, num_args, ...) _VARIADIC(VARIADIC_NAME(name, num_args), num_args, __VA_ARGS__)

#endif

단순화 된 사용 시나리오 :

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
*/

#include "variadic.h"

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

그리고 _generic :

const uint8*
uint16_tobytes(const uint16* in, uint8* out, size_t bytes);

const uint16*
uint16_frombytes(uint16* out, const uint8* in, size_t bytes);

const uint8*
uint32_tobytes(const uint32* in, uint8* out, size_t bytes);

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
Generic function name supported on the non-uint8 type, except where said type
is unavailable because the argument for output buffer was not provided.
*/

#include "variadic.h"

#define   uint16_tobytes_2(a,    c) a, NULL, c
#define   uint16_tobytes_3(a, b, c) a,    b, c
#define   uint16_tobytes(...) VARIADIC(  uint16_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint16_frombytes_2(   b, c) NULL, b, c
#define uint16_frombytes_3(a, b, c)    a, b, c
#define uint16_frombytes(...) VARIADIC(uint16_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   uint32_tobytes_2(a,    c) a, NULL, c
#define   uint32_tobytes_3(a, b, c) a,    b, c
#define   uint32_tobytes(...) VARIADIC(  uint32_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   tobytes(a, ...) _Generic((a),                                                                                                 \
                                   const uint16*: uint16_tobytes,                                                                       \
                                   const uint32*: uint32_tobytes)  (VARIADIC2(  uint32_tobytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

#define frombytes(a, ...) _Generic((a),                                                                                                 \
                                         uint16*: uint16_frombytes,                                                                     \
                                         uint32*: uint32_frombytes)(VARIADIC2(uint32_frombytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

_generic과 결합 할 수없는 Variadic 함수 이름 선택을 사용하여 :

// winternitz() with 5 arguments is replaced with merkle_lamport() on those 5 arguments.

#define   merkle_lamport_5(a, b, c, d, e) a, b, c, d, e
#define   winternitz_7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
#define   winternitz_5_name() merkle_lamport
#define   winternitz_7_name() winternitz
#define   winternitz(...) NVARIADIC(winternitz, NUMARG7(__VA_ARGS__), __VA_ARGS__)

매크로를 사용한 또 다른 트릭 :

#include <stdio.h>

#define func(...) FUNC(__VA_ARGS__, 15, 0)
#define FUNC(a, b, ...) func(a, b)

int (func)(int a, int b)
{
    return a + b;
}

int main(void)
{
    printf("%d\n", func(1));
    printf("%d\n", func(1, 2));
    return 0;
}

하나의 주장 만 통과하면 b 기본값을받습니다 (이 경우 15)

그렇습니다.

typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET;

typedef struct{
    INPUT_SET type;
    char* text;
} input_set1;

typedef struct{
    INPUT_SET type;
    char* text;
    int var;
} input_set2;

typedef struct{
    INPUT_SET type;
    int text;
} input_set3;

typedef union
{
    INPUT_SET type;
    input_set1 set1;
    input_set2 set2;
    input_set3 set3;
} MY_INPUT;

void my_func(MY_INPUT input)
{
    switch(input.type)
    {
        case my_input_set1:
        break;
        case my_input_set2:
        break;
        case my_input_set3:
        break;
        default:
        // unknown input
        break;
    }
}

매크로를 통해

3 매개 변수 :

#define my_func2(...) my_func3(__VA_ARGS__, 0.5)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func3(char a, int b, float c) // b=10, c=0.5
{
    printf("a=%c; b=%d; c=%f\n", a, b, c);
}

네 번째 인수를 원한다면 추가 my_func3을 추가해야합니다. var_func, my_func2 및 my_func의 변경 사항에 주목하십시오

4 개의 매개 변수 :

#define my_func3(...) my_func4(__VA_ARGS__, "default") // <== New function added
#define my_func2(...) my_func3(__VA_ARGS__, (float)1/2)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, _4, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func4, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func4(char a, int b, float c, const char* d) // b=10, c=0.5, d="default"
{
    printf("a=%c; b=%d; c=%f; d=%s\n", a, b, c, d);
}

예외 만 뜨다 변수는 기본값을 제공 할 수 없습니다 (3 매개 변수 케이스에서와 같이 마지막 인수가 아니라면), 그들은 기간 ( '.')이 필요하기 때문에 매크로 논쟁 내에서 받아 들여지지 않습니다. 그러나 my_func2 매크로에서 볼 수 있듯이 주변의 작품을 알아낼 수 있습니다.4 개의 매개 변수의 경우)

프로그램

int main(void)
{
    my_func('a');
    my_func('b', 20);
    my_func('c', 200, 10.5);
    my_func('d', 2000, 100.5, "hello");

    return 0;
}

산출:

a=a; b=10; c=0.500000; d=default                                                                                                                                                  
a=b; b=20; c=0.500000; d=default                                                                                                                                                  
a=c; b=200; c=10.500000; d=default                                                                                                                                                
a=d; b=2000; c=100.500000; d=hello  

왜 우리는 이것을 할 수 없습니다.

선택적 인수에 기본값을 제공하십시오. 그런 식으로 함수의 발신자가 반드시 인수의 가치를 전달할 필요는 없습니다. 인수는 기본값을 취합니다. 그리고 그 주장은 클라이언트에게 선택 사항이됩니다.

예를 들어

void foo (int a, int b = 0);

여기서 B는 선택적 인수입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top