확장 C 매크로 표시
C 매크로를 전개하는 경우 (수동으로 추적하는 것 외에) 어떤 방법이 좋을까요?
예를 들어.GTK_WIDGET_SET_FLAGS
, 매크로(또는 2개)를 사용하는 매크로를 사용합니다.
모든 매크로, 모든 단계를 검색하는 대신 자동으로 확장되는 것을 보고 싶습니다.
갱신하다
cpp를 시도했지만 첫 번째 패스만 한 것 같았다.
온:
GTK_WIDGET_SET_FLAGS(obj, 13)
include 파일을 확장해서
G_STMT_START{ ((GTK_OBJECT_FLAGS (obj)) |= (13)); }G_STMT_END
이것은, 이러한 에러 메세지에 의해서 설명되고 있습니다(-o 파일명을 사용하는 경우).
gtk/gtkwidget.h:34:21:gdk/gdk.h:그런 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:35:31:gtk/gtkaccelgroup.h: 그런 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:36:27: gtk/gtkobject.h: 해당 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:37:31:gtk/gtkadjustment.h: 그런 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:38:26:gtk/gtkstyle.h:그런 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:39:29: gtk/gtksettings.h: 해당 파일 또는 디렉토리가 없습니다.gtk/gtkwidget.h:40:21:atk/atk.h:그런 파일 또는 디렉토리가 없습니다.
gtk, atk 및 gdk 디렉토리는 모두 현재 작업 디렉토리에 있는데 어떻게 하면 cpp에서 검색할 수 있을까요?
그건 그렇고.gcc -E
와 완전히 같은 출력을 제공합니다.cpp
업데이트 2:
포함 경로 문제는 gcc -E를 사용하여 포함 디렉토리를 -I 옵션과 함께 전달하면 해결됩니다.
사용하는 컴파일러에 따라서는, 프리프로세서(매크로 확장을 실시해, 매크로가 컴파일러에 의해서 전혀 인식되지 않는 것)가 끝난 후에 코드를 확인할 수 있는 방법이 있습니다.
gcc의 경우 옵션은 -E 입니다.다음은 실제 GTK+ 매크로가 아닌 장난감 코드를 사용한 간단한 예입니다.
~/tmp> cat cpptest.c
#define SET_FLAGS(w, f) ((w)->flags |= (f))
int main(void)
{
SET_FLAGS(0, 4711);
return 0;
}
~/tmp> gcc -E cpptest.c
# 1 "cpptest.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "cpptest.c"
int main(void)
{
((0)->flags |= (4711));
return 0;
}
GCC-save-temps
이 옵션의 큰 장점은-E
빌드 자체에 큰 간섭 없이 빌드 스크립트에 쉽게 추가할 수 있습니다.
실행 시:
gcc -save-temps -c -o main.o main.c
메인
#define INC 1
int myfunc(int i) {
return i + INC;
}
그리고 이제, 일반적인 출력 외에main.o
현재 작업 디렉토리에는 다음 파일도 포함되어 있습니다.
main.i
는 필요한 사전 교차 파일을 포함하고 있습니다.# 1 "main.c" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "main.c" int myfunc(int i) { return i + 1; }
main.s
는 보너스로 원하는 생성 어셈블리가 포함되어 있습니다..file "main.c" .text .globl myfunc .type myfunc, @function myfunc: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl -4(%rbp), %eax addl $1, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size myfunc, .-myfunc .ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0" .section .note.GNU-stack,"",@progbits
다수의 파일에 대해 이 작업을 수행할 경우 대신 다음을 사용하는 것이 좋습니다.
-save-temps=obj
그러면 중간 파일이 같은 디렉토리에 저장됩니다.-o
현재 작업 디렉토리가 아닌 객체 출력을 통해 잠재적인 기본 이름 충돌을 방지합니다.
또 다른 은 ' 낫다'를 더하면 .-v
:
gcc -save-temps -c -o main.o -v main.c
는, 「인 파일」의 「일시적인 」의 「일시적인 파일」의 「일시적인 파일」이 아닌 「이되고 있는 있습니다./tmp
따라서 전처리/컴파일/어셈블리 단계를 포함하여 정확히 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
Ubuntu 19.04 amd64, GCC 8.3.0에서 테스트 완료.
gcc -E myfile.c
대부분의 IDE는 마우스 포인터가 식별자(또는 다른 방법) 위로 이동하면 확장 버전의 매크로를 편집기에 표시합니다.Eclipse/CDT가 이를 수행하고 Visual Studio가 이를 수행하는 것을 알고 있습니다(적어도 VS 2008은 해당).
컴파일러가 전처리된 출력을 생성하는 것은 까다로운 문제를 추적하는 경우 유용하지만, 매일매일 화면상의 코드에 무슨 일이 일어나고 있는지 알고 싶을 때는 IDE를 사용하는 것이 좋습니다.
-E를 사용하는 경우에도 gcc는 헤더 파일의 경로가 필요합니다.예를 들어, 나는 당신의 헤더를 경로로...
Makefile이 있는 경우 일반적으로 gcc-E를 사용하여 CC를 오버라이드할 수 있습니다.
일반적으로 cpp는 기존과 같이 프리프로세서의 gcc에 플래그를 추가하는 스크립트일 뿐입니다.
다음과 같이 실행 시 매크로 확장을 덤프할 수 있습니다.
#include <stdio.h>
/*
* generic helper macros
*/
#define CALL(macro, arguments) macro arguments
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) # __VA_ARGS__
/*
* dumps a macro and its expansion to stdout
* the second argument is optional and specifies the number of
* arguments that macro takes: 0 means macro takes zero arguments
* no second argument means macro is not function-like
*/
#define DUMP_MACRO(macro, ...) \
do { \
puts ( \
"'" \
# macro STR(DUMP_MACRO_ARGS_ ## __VA_ARGS__) \
"' expands to '" \
STR(CALL(macro, DUMP_MACRO_ARGS_ ## __VA_ARGS__)) \
"'" \
); \
} while (0)
/* helpers for DUMP_MACRO, add more if required */
#define DUMP_MACRO_ARGS_
#define DUMP_MACRO_ARGS_0 ()
#define DUMP_MACRO_ARGS_1 (<1>)
#define DUMP_MACRO_ARGS_2 (<1>, <2>)
#define DUMP_MACRO_ARGS_3 (<1>, <2>, <3>)
/*
* macros to be used in examples for DUMP_MACRO
*/
#define EXAMPLE ( EXAMPLE0() << 9 )
#define EXAMPLE0() __GNUC__
#define EXAMPLE1(EXAMPLE1) EXAMPLE1
#define EXAMPLE3(EXAMPLE1, _, __) ( EXAMPLE1 ? _(__) : false )
int main() {
/* examples */
DUMP_MACRO(EXAMPLE);
DUMP_MACRO(EXAMPLE0, 0);
DUMP_MACRO(EXAMPLE1, 1);
DUMP_MACRO(EXAMPLE3, 3);
DUMP_MACRO(EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol));
/* does not work for DUMP_MACRO itself, because the
preprocessor does not allow recursion */
DUMP_MACRO(DUMP_MACRO, 1);
DUMP_MACRO(DUMP_MACRO, 2);
return 0;
}
프로그램이 인쇄됩니다.
'EXAMPLE' expands to '( 4 << 9 )'
'EXAMPLE0()' expands to '4'
'EXAMPLE1(<1>)' expands to '<1>'
'EXAMPLE3(<1>, <2>, <3>)' expands to '( <1> ? <2>(<3>) : false )'
'EXAMPLE3(EXAMPLE, EXAMPLE1, non_macro_symbol)' expands to '( ( 4 << 9 ) ? non_macro_symbol : false )'
'DUMP_MACRO(<1>)' expands to 'DUMP_MACRO (<1>)'
'DUMP_MACRO(<1>, <2>)' expands to 'DUMP_MACRO (<1>, <2>)'
그러나 이는 완전한 확장만 가져옵니다.단일 단계가 필요한 경우 Eclipse/CDT가 도움이 되지만 사용하는 모든 헤더 및 컴파일러 플래그를 가르쳐야 합니다.
Visual Studio에서는 프리프로세서 결과 변환 유닛파일을 생성할 수 있습니다.프로젝트 옵션, C/C++/Preprocessor로 이동하여 "Generate Preprocessed File" 또는 "Preprocess to a File"을 Yes로 설정할 수 있습니다(또는 /P 또는 /EP 컴파일러 스위치를 사용하여 라인 번호를 포함하는지 여부).
gcc를 사용하는 경우 실행도 실행할 수도 있습니다.
cpp myfile.c
매크로 확장을 담당하는 컴파일러의 프리프로세서 단계만 실행하려고 합니다.위해서gcc
- E잘
소스 파일에서 cpp를 실행해 보십시오.
매크로가 없어질 때까지 gcc - E를 여러 번 실행해 본 적이 있습니까?
대략적인 IDE에 갇혔을 때, 다음과 같은 것을 시도해 보십시오.
#define DISPLAY_VALUE2(x) #x
#define DISPLAY_VALUE(x) DISPLAY_VALUE2(x)
#pragma message("#DEFINE F_CPU " DISPLAY_VALUE(F_CPU))
생산하다
…/sketch_may21a.ino: In function 'void loop()':
…/sketch_may21a.ino:10:54: note: #pragma message: #DEFINE F_CPU 16000000L
#pragma message("#DEFINE F_CPU " DISPLAY_VALUE(F_CPU))
^
http://MicroChip.com/forums/m724722.aspx의 mdematos 덕분에
순진한 어프로치
기본적으로 스트링화 매크로를 다음에 나타냅니다.
#define stringify(exp) #exp
#
는 간단한 단어로 문자열을 만드는 프리프로세서 연산자이므로 를 참조해 주십시오.
문제
요.#define FOO some_expression
로 확장됩니다."FOO"
(그 매크로의 이름)이 아직 확장되지 않았기 때문입니다.
솔루션
그래서 먼저 매크로를 확장한 후 매크로를 삽입하는 특별한 매크로가 있는 것입니다.
#define stringify_m(macro) stringify(macro)
예
조금 더 복잡한 매크로를 예로 들어 보겠습니다.
#define _padding_(size, id) char _padding##id##_ [((size) + sizeof(char) - 1) / sizeof(char)]
stringify_m
음음음같 뭇매하다
stringify_m(_padding_(8, 6502))
결과는 다음과 같습니다.
"char _padding6502_ [((8) + sizeof(char) - 1) / sizeof(char)]"
언급URL : https://stackoverflow.com/questions/985403/seeing-expanded-c-macros
'source' 카테고리의 다른 글
삼각파를 발생시키는 단선 함수가 있나요? (0) | 2022.08.27 |
---|---|
C : typedef 구조명 {...}; VS typedef 구조{...} 이름 (0) | 2022.08.27 |
restrict 키워드는 gcc/g++에 큰 이점이 있습니까? (0) | 2022.08.27 |
불명확한 에러가 내 컴포넌트 이름이 0으로 시작된다고 한다. (0) | 2022.08.27 |
vue.js 및 부트스트랩 4를 사용한 팝오버 (0) | 2022.08.27 |