programing

컴파일 시 함수 파라미터 수 계산

procenter 2022. 9. 24. 22:13
반응형

컴파일 시 함수 파라미터 수 계산

C 라이브러리(C 헤더 포함)는 2개의 다른 버전으로 존재합니다.

그 중 하나는 다음과 같은 기능을 가지고 있습니다.

int test(char * a, char * b, char * c, bool d, int e);

다른 버전은 다음과 같습니다.

int test(char * a, char * b, char * c, bool d)

(e는 함수 파라미터로 제공되지 않지만 함수 자체에 하드 코딩되어 있습니다).

그 않기 버전을 방법만 사용할 수 없습니다.#if ★★★★★★★★★★★★★★★★★」#ifdef버전 번호를 확인합니다.

프로그램 컴파일 시 설치된 버전에 따라 이 라이브러리의 두 가지 버전으로 컴파일할 수 있는 C 프로그램을 작성할 수 있는 방법이 있습니까?이렇게 하면 내 프로그램을 컴파일하려는 기여자들은 라이브러리의 어느 버전을 자유롭게 사용할 수 있고 툴도 컴파일할 수 있습니다.

그래서 명확하게 하기 위해 다음과 같은 것을 찾고 있습니다(또는 이와 유사한 것을 찾고 있습니다.

#if HAS_ARGUMENT_COUNT(test, 5)
    test("a", "b", "c", true, 20);
#elif HAS_ARGUMENT_COUNT(test, 4)
    test("a", "b", "c", true);
#else
    #error "wrong argument count"
#endif

그것을 C로 할 수 있는 방법이 있습니까?나는 방법을 찾을 수 없었다.

라이브러리는 libogc ( https://github.com/devkitPro/libogc )이 됩니다.이것에 의해, 다음의 정의가 변경되었습니다.if_config이전 버전에서도 새 버전에서도 프로그램을 사용할 수 있도록 하고 싶습니다.라이브러리에서 버전 식별자를 찾을 수 없습니다.GCC 8.3은 GCC 8.3입니다.

방법은 이음음음음음음 the the the the the the the the the the the the the this에서 해야 .configure스테이지에서는 Autoconf(또는 CMake, 또는 기타) 테스트 단계를 사용하여 기본적으로 5개의 파라미터 시그니처를 사용하는 작은 프로그램을 컴파일하여 정상적으로 컴파일되는지 확인합니다.사용 중인 라이브러리의 버전을 판별합니다.은, 할 수 있습니다.이는, 「」로 할 수 .#if코드를 차단합니다.

프리프로세싱 단계에서는 이 작업을 수행할 방법이 없다고 생각합니다(적어도 외부 스크립트 없이는).한편, C11을 사용하고 있는 경우는, 컴파일시에 함수의 시그니처를 검출하는 방법이 있습니다._Generic이 ,, 음, 음, 다, 다, 다, 다, 다, 다, 다, 다, 습, 습, ., ., ., ., ., ., ., ., ., like, like, like, like,#if되지 않기 단계에서 1할 수 primary 은 1 또는 2 입니다.

#define WEIRD_LIB_FUNC_TYPE(T) _Generic(&(T), \
    int (*)(char *, char *, char *, bool, int): 1, \
    int (*)(char *, char *, char *, bool): 2, \
    default: 0)

printf("test's signature: %d\n", WEIRD_LIB_FUNC_TYPE(test));
// will print 1 if 'test' expects the extra argument, or 2 otherwise

만약 이것이 당신의 질문에 답하지 못한다면 죄송합니다.헤더 수 는, 「stock」할 수 .#ifdef그 라이브러리의 특정 버전에만 존재하는 것입니다.

이건 그냥 형편없는 도서관 디자인이야.

업데이트: 코멘트를 읽은 후, 향후 독자를 위해 전처리 단계에서는 불가능하지만 컴파일 시에는 가능하다는 점을 명확히 해야 합니다.위의 제 스니펫을 바탕으로 함수 호출을 조건부로 캐스팅하면 됩니다.

typedef int (*TYPE_A)(char *, char *, char *, bool, int);
typedef int (*TYPE_B)(char *, char *, char *, bool);

int newtest(char *a, char *b, char *c, bool d, int e) {
    void (*func)(void) = (void (*)(void))&test;
    if (_Generic(&test, TYPE_A: 1, TYPE_B: 2, default: 0) == 1) {
        return ((TYPE_A)func)(a, b, c, d, e);
    }
    return ((TYPE_B)func)(a, b, c, d);
}

이런 식으로 함수를 캐스팅하는 것은 논란의 여지가 있을 수 있지만 이는 실제로 효과가 있습니다.@ @pizzapants184는 @pizzapants184로 되어 있기 때문에 _Generic콜은 컴파일 시에 평가됩니다.

C에서는 만, 'C'로 경우는요.gcc매우 추악한 방법이 사용될 수 있습니다.gcc aux-info의 수를 전달합니다.-D:

#!/bin/sh

gcc -aux-info output.info demo.c
COUNT=`grep "extern int foo" output.info | tr -dc "," | wc -m`
rm output.info
gcc -o demo demo.c -DCOUNT="$COUNT + 1"
./demo

이 토막

#include <stdio.h>

int foo(int a, int b, int c);

#ifndef COUNT
#define COUNT 0
#endif

int main(void)
{
    printf("foo has %d parameters\n", COUNT);
    return 0;
}

출력

foo has 3 parameters

여러 버전의 정적 라이브러리를 사용하여 코드 컴파일을 지원하려고 해도 도움이 되지 않습니다.최신 릴리스를 사용하도록 코드를 업데이트하고 필요 이상으로 삶을 어렵게 만들지 마십시오.

Dennis Ritchie의 원래 C 언어에서는 함수가 전달된 파라미터 이외의 파라미터에 접근하지 않는 한 예상되는 파라미터의 수에 관계없이 임의의 수의 인수를 전달할 수 있습니다.이 이러한수 에서도, C .이러한 규칙을 에 「」와 같은 있지 않는 .pascal통상의 호출 규약을 사용하는 것을 나타냅니다.

따라서 Ritchie의 원래 C언어로 다음과 같은 동작이 완전히 정의되어 있습니다.

int addTwoOrThree(count, x, y, z)
  int count, x, y, z;
{
  if (count == 3)
    return x+y+z;
  else
    return x+y;
}
int test()
{
  return count(2, 10,20) + count(3, 1,2,3);
}

디폴트로는 이러한 유연성을 지원하는 것이 비현실적인 플랫폼이 일부 있기 때문에 C 표준에서는 컴파일러가 예상보다 인수가 많거나 적은 함수에 대한 콜을 의미 있게 처리하도록 요구하지 않습니다.단, 이 함수는 다음과 같이 선언되어 있습니다....parameter는 적어도 실제 지정된 파라미터의 수만큼 큰 인수를 "수정"합니다.따라서 Ritchie의 언어에 존재하는 유연성을 이용하는 코드가 작성된 것은 드문 일이다.그럼에도 불구하고, 호출되는 함수가 발신자와 다른 컴파일 유닛에 있고, 호출되는 컴파일 유닛 내에서 선언되었지만 프로토타입이 아닌 경우, 많은 구현은 여전히 그 패턴을 지원하기 위해 작성된 코드를 받아들입니다.

넌 아냐.

사용하고 있는 툴은 정적으로 링크되어 있어 버전 관리를 지원하지 않습니다.지금까지 말한 모든 트릭과 팁을 사용하여 회피할 수 있지만, 결국 그것들은 이 문맥에서는 의미가 없는 추악한 패치워크입니다.

설치한 툴킷 버전에 맞는 코드를 설계합니다.어려운 요구 사항입니다.또한 왜 다른 버전으로 빌드할 수 있도록 게임큐브/하드웨어 코드를 디자인하고 싶은지 이해할 수 없습니다.툴킷은 항상 변경되어 버그나 전제 조건 등을 수정하고 있습니다.코드에 버그가 있거나 잘못된 행동을 할 가능성이 있는 오래된 버전을 사용하고 싶은 경우 등은 고객님의 책임입니다.

끊임없이 진화하는 툴킷을 사용하여 이 작업을 수행할 필요가 있거나 하고 싶다면 여기서 어떤 종류의 엉터리 작업을 다루고 있는지 깨달아야 합니다.

저도 그렇게 생각합니다만, 이것은 당신과 DevKitPro와의 관계를 알고 있기 때문입니다.이전 버전이 설치되어 있고 CI 빌드는 (도커에서) 최신 버전을 사용하기 때문에 작동하지 않습니다.또는 빌드하는 다른 프로젝트의 여러 버전이 컴퓨터에 설치되어 있습니다(단, 이상한 이유로 소스를 업데이트하지 않습니다).

사용하시는 컴파일러가 2020년 11월의 GCC 10과 같은 최신 GCC인 경우, 헤더 파일의 시그니처를 체크하기 위해 독자적인 GCC 플러그인을 작성할 수 있습니다(적절하고 관련된 C 프리프로세서를 내보냅니다).#define- 및/또는#ifdef, (a la GNU autoconf)플러그인이 (예를 들어) sqlite 데이터베이스를 채우고 나중에 sqlite 데이터베이스를 생성할 수 있습니다.#include-d 헤더 파일

그런 다음 필요에 따라 GCC 플러그인과 GCC가 계산한 데이터를 사용하도록 빌드 자동화(예: )를 설정합니다.

단일 기능에 대해 이러한 접근법은 과잉 살상입니다.

일부 대형 프로젝트의 경우, 특히 GCC 플러그인에서 일부 프로젝트별 코딩 규칙 검증 프로그램도 코드화하기로 결정한 경우 이 방법이 유용할 수 있습니다.

GCC 플러그인의 기입에는 몇 주가 걸릴있습니다.또, 장래의 GCC 11로 전환할 때는, 플러그 인의 소스 코드를 패치 할 필요가 있습니다.

또한 이 보고서 초안 및 유럽 CARTICE DECORDER 프로젝트(이 보고서에 설명된 작업의 자금 지원)를 참조하십시오.

참고로 라이브러리 작성자에게 버전 메타데이터를 추가하도록 요청할 수 있습니다.영감은 libonion, Glib 또는 libgccjit에서 얻을 수 있습니다.

BTW, 호에서 올바르게 설명했듯이 일부 오픈소스 라이브러리의 유지보수가 이루어지지 않은 이전 버전을 사용하면 안 됩니다.작업한 것을 사용하세요.

구버전과 신버전을 모두 사용할 수 있도록 하고 싶습니다.

왜요?

프로그램이 이전 버전의 libogc에서 작동하도록 하는 것은 당신과 그들 모두에게 부담을 가중시킵니다.당신이 그렇게 하지 않을 수 있다면 왜 오래된 도서관에 의존하는지 이해가 안 가네요.


PS. 물론 GCC 8용 플러그인을 작성할 수 있습니다.GCC 10으로 전환하는 것을 추천합니다.GCC 10은 확실히 개선되었습니다.

이것이 당신의 구체적인 문제를 해결하거나 전혀 도움이 될지는 모르겠지만, 여기 Laurent Deniau에 의해 컴파일 함수에 전달된 인수 수를 세는 프리프로세서 장치가 있습니다.

무슨 뜻인가 하면args_count(a,b,c)(컴파일 시에) 일정한 리터럴 상수로 평가하다3, 등args_count(__VA_ARGS__)(바이어딕 매크로 내)는 (컴파일 시) 매크로에 전달된 인수 수에 따라 평가됩니다.

이를 통해 예를 들어 인수 수를 지정하지 않고 variadic 함수를 호출할 수 있습니다.이는 프리프로세서가 이를 대신하기 때문입니다.

그래서, 만약 당신이 가변 함수를 가지고 있다면

void function_backend(int N, ...){
  // do stuff
}

여기서 (일반적으로) 인수 수를 전달해야 합니다.N, 「프런트 엔드」의 가변 매크로를 쓰는 것으로, 이 프로세스를 자동화할 수 있습니다.

#define function_frontend(...) function_backend(args_count(__VA_ARGS__), __VA_ARGS__)

그리고 이제 네가 전화한다.function_frontend()원하는 수의 인수를 사용하여 다음을 수행합니다.

가 유튜브 튜토리얼을 만들어 드렸는데요.

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

#define m_args_idim__get_arg100(                                                                    \
  arg00,arg01,arg02,arg03,arg04,arg05,arg06,arg07,arg08,arg09,arg0a,arg0b,arg0c,arg0d,arg0e,arg0f,  \
  arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17,arg18,arg19,arg1a,arg1b,arg1c,arg1d,arg1e,arg1f,  \
  arg20,arg21,arg22,arg23,arg24,arg25,arg26,arg27,arg28,arg29,arg2a,arg2b,arg2c,arg2d,arg2e,arg2f,  \
  arg30,arg31,arg32,arg33,arg34,arg35,arg36,arg37,arg38,arg39,arg3a,arg3b,arg3c,arg3d,arg3e,arg3f,  \
  arg40,arg41,arg42,arg43,arg44,arg45,arg46,arg47,arg48,arg49,arg4a,arg4b,arg4c,arg4d,arg4e,arg4f,  \
  arg50,arg51,arg52,arg53,arg54,arg55,arg56,arg57,arg58,arg59,arg5a,arg5b,arg5c,arg5d,arg5e,arg5f,  \
  arg60,arg61,arg62,arg63,arg64,arg65,arg66,arg67,arg68,arg69,arg6a,arg6b,arg6c,arg6d,arg6e,arg6f,  \
  arg70,arg71,arg72,arg73,arg74,arg75,arg76,arg77,arg78,arg79,arg7a,arg7b,arg7c,arg7d,arg7e,arg7f,  \
  arg80,arg81,arg82,arg83,arg84,arg85,arg86,arg87,arg88,arg89,arg8a,arg8b,arg8c,arg8d,arg8e,arg8f,  \
  arg90,arg91,arg92,arg93,arg94,arg95,arg96,arg97,arg98,arg99,arg9a,arg9b,arg9c,arg9d,arg9e,arg9f,  \
  arga0,arga1,arga2,arga3,arga4,arga5,arga6,arga7,arga8,arga9,argaa,argab,argac,argad,argae,argaf,  \
  argb0,argb1,argb2,argb3,argb4,argb5,argb6,argb7,argb8,argb9,argba,argbb,argbc,argbd,argbe,argbf,  \
  argc0,argc1,argc2,argc3,argc4,argc5,argc6,argc7,argc8,argc9,argca,argcb,argcc,argcd,argce,argcf,  \
  argd0,argd1,argd2,argd3,argd4,argd5,argd6,argd7,argd8,argd9,argda,argdb,argdc,argdd,argde,argdf,  \
  arge0,arge1,arge2,arge3,arge4,arge5,arge6,arge7,arge8,arge9,argea,argeb,argec,arged,argee,argef,  \
  argf0,argf1,argf2,argf3,argf4,argf5,argf6,argf7,argf8,argf9,argfa,argfb,argfc,argfd,argfe,argff,  \
  arg100, ...)  arg100
#define m_args_idim(...)  m_args_idim__get_arg100(, ##__VA_ARGS__,                  \
  0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0,  \
  0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,0xe7,0xe6,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0,  \
  0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd0,  \
  0xcf,0xce,0xcd,0xcc,0xcb,0xca,0xc9,0xc8,0xc7,0xc6,0xc5,0xc4,0xc3,0xc2,0xc1,0xc0,  \
  0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0,  \
  0xaf,0xae,0xad,0xac,0xab,0xaa,0xa9,0xa8,0xa7,0xa6,0xa5,0xa4,0xa3,0xa2,0xa1,0xa0,  \
  0x9f,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96,0x95,0x94,0x93,0x92,0x91,0x90,  \
  0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83,0x82,0x81,0x80,  \
  0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70,  \
  0x6f,0x6e,0x6d,0x6c,0x6b,0x6a,0x69,0x68,0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60,  \
  0x5f,0x5e,0x5d,0x5c,0x5b,0x5a,0x59,0x58,0x57,0x56,0x55,0x54,0x53,0x52,0x51,0x50,  \
  0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40,  \
  0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,  \
  0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,  \
  0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,  \
  0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,  \
)

typedef struct{
  int32_t x0,x1;
}ivec2;
int32_t max0__ivec2(int32_t nelems, ...){  // The largest component 0 in a list of 2D integer vectors
  int32_t max = ~(1ll<<31) + 1;  // Assuming two's complement
  va_list args;
  va_start(args, nelems);
  for(int i=0; i<nelems; ++i){
    ivec2 a = va_arg(args, ivec2);
    max = max > a.x0 ? max : a.x0;
  }
  va_end(args);
  return max;
}
#define max0_ivec2(...)  max0__ivec2(m_args_idim(__VA_ARGS__), __VA_ARGS__)

int main(){
  int32_t max = max0_ivec2(((ivec2){0,1}), ((ivec2){2,3}, ((ivec2){4,5}), ((ivec2){6,7})));
  printf("%d\n", max);
}

언급URL : https://stackoverflow.com/questions/64888608/figure-out-function-parameter-count-at-compile-time

반응형