source

printf()를 함수 또는 매크로로 랩하는 방법

goodcode 2022. 8. 25. 23:53
반응형

printf()를 함수 또는 매크로로 랩하는 방법

면접 질문처럼 들릴 수 있지만 실제로는 현실적인 문제입니다.

저는 임베디드 플랫폼을 사용하고 있으며, 이러한 기능에 해당하는 기능만 사용할 수 있습니다.

  • printf()
  • snprintf()

①은,printf()구현(및 시그니처)은 가까운 장래에 변경될 가능성이 있기 때문에 나중에 쉽게 이행할 수 있도록 구현(및 시그니처)에 대한 콜은 별도의 모듈에 존재해야 합니다.

이를 위해 로깅 콜을 일부 함수 또는 매크로로 랩할 수 있습니까?가 「」를 호출하는 입니다.THAT_MACRO("Number of bunnies: %d", numBunnies);단, 위의 함수에 대한 호출은 한 곳에서만 볼 수 있습니다.

파파러:arm-gcc -std=c99

편집: 예를 들어 2000년 이후 베스트 프랙티스와 아마 훨씬 이전 단계에서 인라인 함수는 여러 가지 이유로 매크로보다 훨씬 우수합니다.

여기에는 다음 두 가지 방법이 있습니다.

  1. 변종 매크로

    #define my_printf(...) printf(__VA_ARGS__)
    
  2. 「」를 전송 va_args

    #include <stdarg.h>
    #include <stdio.h>
    
    void my_printf(const char *fmt, ...) {
        va_list args;
        va_start(args, fmt);
        vprintf(fmt, args);
        va_end(args);
    }
    

, 또다있 there라는 것도 .vsnprintf,vfprintf 할 수 것은 이든지.stdio.

C99 를 사용할 수 있기 때문에, Variadic 매크로로 랩합니다.

#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)

이 있다고vprintf뭐그 、 거잖잖요요요 요잖요요 。만약 그런 것이 있다면, 당신은 그것을 세르게이 L이 그의 답변에서 제공한 것과 같은 기능으로 포장할 수 있습니다.


위의 TM_PRINTF는 빈 VA_ARGS 목록에서는 작동하지 않습니다.적어도 GCC에서는 다음을 작성할 수 있습니다.

#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)

는 앞에 합니다.__VA_ARGS__어어있있있있다다

#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)

##하면 "token"이 사용됩니다.TM_PRINTF("aaa");

이것은 로그 전 시간을 인쇄하는 @ldav1의 우수한 답변의 약간 변경된 버전입니다.

#define TM_PRINTF(f_, ...)                                                                            \
{                                                                                                 \
    struct tm _tm123_;                                                                            \
    struct timeval _xxtv123_;                                                                     \
    gettimeofday(&_xxtv123_, NULL);                                                               \
    localtime_r(&_xxtv123_.tv_sec, &_tm123_);                                                     \
    printf("%2d:%2d:%2d.%d\t", _tm123_.tm_hour, _tm123_.tm_min, _tm123_.tm_sec, _xxtv123_.tv_usec); \
    printf((f_), ##__VA_ARGS__);                                                                  \
};
#define PRINTF(...) printf(__VA_ARGS__)

다음과 같이 동작합니다.

PRINTF를 하여 무한 후합니다.PRINTF(...)로로 합니다.printf(__VA_ARGS__)__VA_ARGS__는 매개 변수화된 매크로 정의에서 지정된 인수를 나타내기 위해 사용됩니다(무한 인수에 이름을 붙일 수 없기 때문에).

콜을 2개의 괄호로 묶을 필요가 있는 경우는, 다음과 같이 할 수 있습니다.

#define THAT_MACRO(pargs)    printf pargs

그 후 사용합니다.

THAT_MACRO(("This is a string: %s\n", "foo"));
           ^
           |
          OMG

이것은 프리프로세서의 관점에서 인수의 전체 목록이 하나의 매크로 인수가 되어 괄호로 대체되기 때문에 작동합니다.

이것은 그냥 하는 것보다 낫다.

#define THAT_MACRO printf

이를 통해 다음과 같이 정의할 수 있습니다.

#define THAT_MACRO(pargs)  /* nothing */

이것은 매크로 인수를 "먹어버리고" 컴파일된 코드의 일부가 되지 않습니다.

업데이트 물론 C99에서는 이 기술은 사용되지 않습니다. 그냥 가변 매크로를 사용하고 행복하십시오.

제한된 라이브러리?임베디드 시스템?최대한의 퍼포먼스가 필요합니까?문제없어!

질문에 대한 답변에서 알 수 있듯이 어셈블리 언어를 사용하여 VA_LIST를 허용하지 않는 함수를 VA_LIST를 사용할 수 있는 함수로 래핑할 수 있습니다.따라서 적은 비용으로 자체 vprintf를 구현할 수 있습니다.

이 방법은 작동하며, 거의 확실하게 원하는 추상화 기능을 얻을 수 있지만, uClibc의 일부를 슬라이스함으로써 기능이 가득 찬 표준 라이브러리를 얻을 것을 권장합니다.모든 사이클이 반드시 필요한 경우를 제외하고, 이러한 솔루션은 조립품을 사용하는 것보다 휴대성이 뛰어나고 전반적으로 유용한 답변이 될 것입니다.

결국 그런 프로젝트가 존재하는 이유이기도 합니다.

언급URL : https://stackoverflow.com/questions/20639632/how-to-wrap-printf-into-a-function-or-macro

반응형