Preprocesor zrzutu GCC definiuje

Odpowiedzi:

304

Tak, użyj -E -dMopcji zamiast -c. Przykład (wyprowadza je na standardowe wyjście):

 gcc -dM -E - < /dev/null

Dla C ++

 g++ -dM -E -x c++ - < /dev/null

Z podręcznika gcc :

Zamiast normalnego wyjścia wygeneruj listę dyrektyw `#define 'dla wszystkich makr zdefiniowanych podczas wykonywania preprocesora, w tym predefiniowanych makr. To pozwala ci dowiedzieć się, co jest wstępnie zdefiniowane w twojej wersji preprocesora. Zakładając, że nie masz pliku foo.h, polecenie

touch foo.h; cpp -dM foo.h

pokaże wszystkie predefiniowane makra.

Jeśli użyjesz -dM bez opcji -E, -dM jest interpretowany jako synonim -fdump-rtl-mach.

filant
źródło
4
gcc istnieje w systemach, w których / dev / null nic nie znaczy.
Pavel P
4
@Pavel, możesz użyć pustego pliku z gcc lub preprocesorem - cpp.
filant
16
Jako alternatywną odpowiedź dodałem bardziej przenośne podejście: echo | gcc -dM -E -działa również w systemie Windows.
Pavel P
4
Czy można ustalić, skąd (tj. W jakim pliku) pochodzą te definicje?
edam
2
Alternatywnie, w systemie Windows, cpp -dM -E - < NULmożna użyć.
René Nyffenegger,
78

Zwykle robię to w ten sposób:

$ gcc -dM -E - < /dev/null

Zauważ, że niektóre definicje preprocesora zależą od opcji wiersza poleceń - możesz je przetestować, dodając odpowiednie opcje do powyższego wiersza poleceń. Na przykład, aby zobaczyć, które opcje SSE3 / SSE4 są domyślnie włączone:

$ gcc -dM -E - < /dev/null | grep SSE[34]
#define __SSE3__ 1
#define __SSSE3__ 1

a następnie porównaj to, gdy -msse4określono:

$ gcc -dM -E -msse4 - < /dev/null | grep SSE[34]
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSSE3__ 1

Podobnie możesz zobaczyć, które opcje różnią się między dwoma różnymi zestawami opcji wiersza poleceń, np. Porównaj definicje preprocesora dla poziomów optymalizacji -O0(brak) i -O3(pełny):

$ gcc -dM -E -O0 - < /dev/null > /tmp/O0.txt
$ gcc -dM -E -O3 - < /dev/null > /tmp/O3.txt
$ sdiff -s /tmp/O0.txt /tmp/O3.txt 
#define __NO_INLINE__ 1        <
                               > #define __OPTIMIZE__ 1
Paul R.
źródło
45

Późna odpowiedź - uznałem inne odpowiedzi za przydatne - i chciałem dodać trochę więcej.


Jak zrzucić makra preprocesora pochodzące z określonego pliku nagłówka?

echo "#include <sys/socket.h>" | gcc -E -dM -

lub (dzięki @mymedia za sugestię):

gcc -E -dM -include sys/socket.h - < /dev/null

W szczególności chciałem zobaczyć, co SOMAXCONN został zdefiniowany w moim systemie. Wiem, że mogłem po prostu otworzyć standardowy plik nagłówka, ale czasami muszę się trochę rozejrzeć, aby znaleźć lokalizację pliku nagłówka. Zamiast tego mogę po prostu użyć tej linijki:

$ gcc -E -dM -include sys/socket.h - < /dev/null | grep SOMAXCONN
#define SOMAXCONN 128
$ 
Cyfrowa trauma
źródło
1
możesz użyć opcji -include kompilatora, aby uniknąć potoków
mymedia
31

Proste podejście ( gcc -dM -E - < /dev/null) działa dobrze w przypadku gcc, ale nie działa w przypadku g ++. Ostatnio wymagałem testu funkcji C ++ 11 / C ++ 14. Zalecenia dotyczące odpowiadających im nazw makr są publikowane na stronie https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations . Ale:

g++ -dM -E - < /dev/null | fgrep __cpp_alias_templates

zawsze kończy się niepowodzeniem, ponieważ po cichu wywołuje sterowniki C (tak jakby były wywoływane przez gcc). Można to zobaczyć, porównując dane wyjściowe z gcc lub dodając opcję wiersza polecenia specyficzną dla g ++, taką jak (-std = c ++ 11), która emituje komunikat o błędzie cc1: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C.

Ponieważ gcc (inne niż C ++) nigdy nie będzie obsługiwał „Aliasów szablonów” (patrz http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf ), musisz dodać -x c++opcję do -x c++wymuś wywołanie kompilatora C ++ (Kredyty za korzystanie z opcji zamiast pustego pliku zastępczego przejdź do yuyichao, patrz poniżej):

g++ -dM -E -x c++ /dev/null | fgrep __cpp_alias_templates

Nie będzie danych wyjściowych, ponieważ g ++ (wersja 4.9.1, domyślnie -std = gnu ++ 98) domyślnie nie włącza funkcji C ++ 11. Aby to zrobić, użyj

g++ -dM -E -x c++ -std=c++11 /dev/null | fgrep __cpp_alias_templates

co ostatecznie ustępuje

#define __cpp_alias_templates 200704

zauważając, że g ++ 4.9.1 obsługuje po wywołaniu „Alias ​​szablonów” -std=c++11.

hermannk
źródło
7
Nie musisz używać fikcyjnego pliku. GCC obsługuje -xargument, więc g++ -x c++ -dM -E -std=c++11 - < /dev/null | grep cpppowinno działać.
yuyichao
@yuyichao Dziękujemy, dzięki temu jest łatwiejszy w użyciu. Nie wiedziałem o opcji -x. Przejrzałem komentarz i włączyłem go do oryginalnej odpowiedzi.
hermannk
23

Przenośne podejście, które działa równie dobrze w systemie Linux lub Windows (gdzie nie ma / dev / null):

echo | gcc -dM -E -

W przypadku c ++ możesz użyć (zamień na c++11dowolną używaną wersję):

echo | gcc -x c++ -std=c++11 -dM -E -

Działa, mówiąc gcc, aby wstępnie przetworzył standardowe wejście (które jest wytwarzane przez echo) i wypisał wszystkie definicje preprocesora (wyszukaj -dletters). Jeśli chcesz wiedzieć, jakie definicje są dodawane po dołączeniu pliku nagłówka, możesz użyć -dDopcji podobnej do -dM, ale nie zawierającej predefiniowanych makr:

echo "#include <stdlib.h>" | gcc -x c++ -std=c++11 -dD -E -

Należy jednak pamiętać, że puste dane wejściowe nadal generują wiele definicji z -dDopcją.

Pavel P.
źródło
6
@rubenvb nie ma znaczenia. chodzi o to, aby mieć linię cmd, która działa równie dobrze co najmniej w systemach Windows i Unix. Jeśli użyjesz NUL, wrócisz do punktu wyjścia: nie będzie działać na systemach, które go nie mają.
Pavel P
2
dodanie pełnej odpowiedzi dla C ++ działa zarówno w systemie Windows, jak i Linux (choć sortzachowuje się trochę inaczej):echo | gcc -x c++ -std=c++17 -dM -E - | sort
Xeverous
To powoduje puste wyjście w git-bash.
Lennart Rolland
@LennartRolland czy ma gcc? W mojej git-bash nie mogę uruchomić gcc
Pavel P
@pavel Używam mingw32 gcc, który jest dostarczany z binarną dystrybucją Qt5 dla systemu Windows.
Lennart Rolland
3

Podczas pracy w dużym projekcie, który ma złożony system kompilacji i gdzie trudno jest uzyskać (lub zmodyfikować) polecenie gcc / g ++ bezpośrednio, istnieje inny sposób, aby zobaczyć wynik ekspansji makr. Po prostu przedefiniuj makro, a otrzymasz wynik podobny do następującego:

file.h: note: this is the location of the previous definition
#define MACRO current_value
Piotr Pałucki
źródło
Szukam flagi, która jest do tego używana. Czy wiesz ?
Welgriv