printf
C++에서 printf 사용시에 format을 잘못 지정하였다면 이렇게 컴파일러단에서 C4477 C4313 C6067 의 워링 에러가 발생하여 잘못된 포맷으로 인한 오류나 크래시를 방지 할 수 있다.
vprintf, vsprintf...
하지만 보통 printf를 저렇게 사용하는 일은 거의 없다.
아래와 같이 보통 로그를 남기는 함수를 va_list를 사용하여 커스터마이징하곤 한다. (UE_LOG도..)
하지만 이렇게 사용하면 포맷 관련 warning이 발생하지 않아서 실수를 저지르기가 너무 쉽다.
해결법
MSVS에서는 저런 사용자 함수에서 포맷 체크를 하는 방법이 없어서 이렇게 편법으로 Debug 빌드 시에만 printf로 체크하는 방식이 가능하다.
sizeof() 안에 있는 printf구문은 런타임에 평가되지 않으므로 문제가 발생하지 않으니 걱정하지 않아도 된다.
#include <stdio.h>
#include <stdarg.h>
void Log(const char* szFormat, ...)
{
va_list lpStart;
va_start(lpStart, szFormat);
vprintf(szFormat, lpStart);
va_end(lpStart);
}
#ifdef _DEBUG
#define CHECK_FORMAT(...) \
do { \
char const dummy = sizeof(printf(__VA_ARGS__)); \
(void)dummy; \
} while (false)
#else
#define CHECK_FORMAT(...) __noop
#endif
#define LOG(...) { CHECK_FORMAT(__VA_ARGS__); Log(__VA_ARGS__); }
int main() {
int a = 5;
LOG("a : %s", a);
return 0;
}
GCC?
이 방법은 MSVC에서만 쓰는 방식이고 GCC에서는 attribute라는 구문으로 포맷 체크를 할 수 있다고 하니 참고 바란다.
attribute((format(printf, formatStringIndex, formatArgStartIndex))).
'Programming > C++ & Unreal' 카테고리의 다른 글
StackWalk64가 context에 의하여 Access violation를 유발 (1) | 2023.10.23 |
---|---|
C++ 가변인자(va_list)를 오버로딩 하지 말자. (1) | 2023.10.23 |
C++ parallel for_each (thread) exception (1) | 2023.10.23 |
C++ RTTI 구현 (0) | 2021.05.02 |
Xcode tbb 설치 (0) | 2020.12.06 |