2009-07-24 10 views
2

전 처리기의 도움으로 C의 일부 함수의 동작을 변경하려고합니다.컴파일시 C 함수 데코레이터 (래퍼)

#ifdef OPT_PARAM 
    #define my_func(a, b, opt) _my_func(a, b, opt) 
#else 
    #define my_func(a, b, opt) _my_func(a, b) 
#endif 

/*the rest of the code always calls "my_func" with all the params 
and not the underscored version...*/ 

#ifdef OPT_PARAM 
void _my_func(int a, int b, int opt) 
#else 
void _my_func(int a, int b) 
#endif 
{ 
    /*... more #ifdefs surrounding opt uses */ 
} 

이 문제가 조건부 함수에 포장하는 패턴이 유사하지만, : 또한

선택적 매개 변수에 대한 기본 패턴은 쉽습니다 ... 오프에 설정하거나 할 수있는 선택적 매개 변수를 추가 밑줄이 합쳐지기 시작합니다 (중첩의 각 레벨에 대해 하나씩, 다른 함수가 될 수도 있고, 래핑되지 않은 경우 다음 레벨에 #define 만있을 수도 있습니다).

여기 코드 복잡도를 줄이는 방법에 대한 아이디어가 있습니까?

P. 나는 파이썬을 기꺼이 사용할 것입니다. 그러나 이것은 드라이버를위한 것입니다 :-(

+0

가변 인수 기능을 사용 하시겠습니까? http://en.wikipedia.org/wiki/Varargs#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D – Inshallah

+0

분명히 나는 ​​그들을 원하지 않는다!^_^나는 이미 그것들을 사용했고 정적 유형 검사를 잃는 것에 대해 매우 걱정하고 있습니다. – fortran

+1

아마도 나는 뭔가를 놓치고 있지만 이것은 나에게 좋을 것 같습니다. 여분의 복잡성은 어디에 있습니까? 그리고 그것은 무엇이 중첩 된 것입니까? –

답변

0

입니다 그냥 균일하게 추가 매개 변수를 처리하고보다 설명적인 이름으로 모호한 밑줄을 변경 새로운 장식을 추가했습니다.

이제 런타임 오버 헤드없이 컴파일 타임에 동작을 플러그 앤 플러그 할 수있는 직교 설계가되었습니다.

2

기본 인수 나 C에서 사용할 수없는 것을 사용하고 싶은 것 같습니다. 이것은 나쁜 생각 인 것 같습니다. 인수를 지정하지 않으려면 그냥 NULL 또는 -1 (표준)를 통과보다 C 패션에서 일을 처리하지.

void function (int a, int b, int c) { 
    if (c != -1) { 
    // something 
    } 
} 

function(a,b,-1); 
function(a,b,c); 
+0

디버깅 용입니다. 최종 빌드에서 추가 매개 변수를 제거해야합니다 ... 어쨌든 중첩 래퍼의 문제를 해결하지 못합니다. -s – fortran

+0

필자는 선택적 매개 변수를 사용하려고합니다. 설정되어 있으면 my_func (a, b, opt)를 호출하고 그렇지 않으면 my_func (a, b)를 호출합니다. – Gert

+0

@fortran : 왜 중첩이 필요합니까? 각 기능에 대해 두 가지 이상의 버전 (디버그 및 최종 버전)이 있습니까? – Christoph

1

을 나는 이것이 당신이 원하는 가까이있을 수 있다고 생각하지만, 나는 확신 할 수 없다. 내 생각에 유형이 검사되고 컴파일 타임에 제거 될 수있는 임의의 수의 인수를 가진 c 함수를 허용하는 것이 아이디어이다.

아래에서 표준을 인용하여 식별자의 점수 예약 된 식별자로 실행할 수 있습니다. 그러나, 이것의 가능성은 나에게 알려지지 않았다.

ISO/IEC 9899 : 1999 (E) 7.1.3

- 밑줄과 대문자 문자 또는 다른 밑줄로 시작하는 모든 식별자는 항상 사용하기 위해 예약 있습니다.

이 솔루션에는 GCC가 필요합니다. GCC 버전은 약한 기호도 지원해야합니다. 아이디어는 컴파일러가 약한 기호를 사용하여 올바른 함수 정의를 찾도록 허용하는 것입니다. 또한 함수의 내용은 즉, 컴파일러가 죽은 가지를 가지 치기해야 지식을 사용하여 단순화 :

if (0) { ... } 

을 추가 분석 (GCC 4.x를 확실하게이 작업을 수행)하지 않고 컴파일시. 존재하지 않는 선택적 매개 변수를 c 전처리 기 (cpp) 기호로 정의하면 함수 본문에 cpp 조건부가있는 것을 피할 수 있습니다 (필요한 경우). 아래의 f_opt0에 대해 opt1 및 opt2가 정의 된 방법을 확인하십시오.

#include <assert.h> 
#include <stdio.h> 

extern void f_opt0(int a, int b) __attribute__((weak)); 
extern void f_opt1(int a, int b, int opt1) __attribute__((weak)); 
extern void f_opt2(int a, int b, int opt1, int opt2) __attribute__((weak)); 

#ifdef OPT0 
void f_opt0(int a, int b) { 
#define opt1 0 
#define opt2 0 
#endif 
#ifdef OPT1 
void f_opt1(int a, int b, int opt1) { 
#define opt2 0 
#endif 
#ifdef OPT2 
void f_opt2(int a, int b, int opt1, int opt2) { 
#endif 
    if (opt1) printf("opt1=%d\n", opt1); 
    if (opt2) printf("opt2=%d\n", opt2); 
    printf("a+b=%d\n", a+b); 
    #undef opt1 
    #undef opt2 
} 

#define f(a, b, o1, o2) \ 
    if (f_opt2) f_opt2(a, b, o1, o2); \ 
    else if (f_opt1) f_opt1(a, b, o1); \ 
    else if (f_opt0) f_opt0(a, b); \ 
    else { assert(0 && "no f() defined!"); } 

int main(void) { 
    f(1, 2, 1, 1); 
    return 0; 
} 

내 테스트는 매우 제한적이었고, 나는이 문제에 경향이 보이고 이해하기 곤란하다 C.이 좋은 디자인을 옹호하지 않습니다. 그러나 그것이 당신의 목표를 만족 시키길 바랍니다.

2

C++ 컴파일러를 사용할 수 있습니까? (함수의 오버로드)을 사용할 수 있습니다.

또 다른 옵션은 결국

#ifdef OPT_PARAM 
# define OPT(X) , X 
#else 
# define OPT(X) 
#endif 

int my_func(int a, int b OPT(int opt)) { 
#ifndef OPT_PARAM 
    int opt = default_value; 
#endif 
    ... // Rest of code 
} 


... 
// calling it 
my_func(2, 4 OPT(42));