Visual C++ - C99 표준의 Compund Literals 빌드 방법
Visual Studio에서 C++ 프로젝트를 생성해 ffmpeg 라이브러리의 헤더를 사용하는 경우, av_ts2str이나, av_ts2timestr 같은 매크로 함수를 사용하게 되면 컴파일 오류가 발생합니다.
왜냐하면, 해당 소스 코드들이 복합 리터럴을 사용하기 때문인데요,
static inline char *av_ts_make_string(char *buf, int64_t ts)
{
if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS");
else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%" PRId64, ts);
return buf;
}
#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts)
이것을 다음의 코드로 간단하게 재현할 수 있습니다.
#include <stdio.h>
void func(int* p)
{
}
int main()
{
func((int[]) { 1, 2, 3, 4, 5 });
return 0;
}
컴파일하면 다음의 오류가 발생하는데요,
Error C4576 a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax
^^ 저처럼, 90년대에 C/C++ 언어를 배운 사람은 저런 구문조차 낯설을 텐데요, 그냥 간단하게 말해서 "익명 인스턴스" 구문이 C99 표준에 포함이 된 것입니다.
재미있는 것은, 저 복합 리터럴 구문이 C++에는 없고 C 언어에만 있다는 점입니다. 그래서, gcc로 저 구문을 컴파일해도 Visual C++와 (메시지는 다르지만) 마찬가지의 오류가 발생합니다.
$ gcc main.cpp
main.cpp: In function ‘int main()’:
main.cpp:10:15: error: taking address of temporary array
10 | func((int[]) { 1, 2, 3, 4, 5 });
| ^~~~~~~~~~~~~~~~~
그러니까, 결국 이 오류를 해결하려면 확장자를 (.cpp가 아닌) ".c"로 바꾸든가, 아니면 해당 cpp 파일의 컴파일 모드를 "Compile as C Code (/TC)"로 변경해야 합니다.
참고로, gcc의 경우라면 "-x c" 옵션을 지정해 C 모드로 컴파일할 수 있습니다.
$ gcc -x c main.cpp
엎어진 김에 쉬어간다고, 이참에 C99에서 추가된 기능 3가지를 살펴보고 가시면 좋겠죠? ^^
[C99] C언어에서 표준 bool 타입 사용하기
; https://karupro.tistory.com/15
[C99] 포인터 최적화를 위한 restrict 키워드
; https://karupro.tistory.com/17
[C99] Compund Literals, C에서의 이름없는 임시 객체
; https://karupro.tistory.com/18
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]