2016-02-13 8 views
9

Jeśli zdefiniuję makro jako #define LOGIC_ONE 1 i chcę użyć LOGIC_ONE w instrukcji sprawy, jaki typ jest uważany za LOGIC_ONE?Jakiego rodzaju makro jest brane pod uwagę?

Czy jest rozpoznawany jako int, ponieważ definiuję go dla wartości 1?

+1

Aby zobaczyć, co preprocesor nie przechodzą '-E' do kompilatora. (msvc, gcc, clang all accept '-E') – Ben

Odpowiedz

19

Makra C++ to proste zamienniki tekstu.

W momencie uruchamiania kompilatora, Twój LOGIC_ONE został już zastąpiony przez prekompilator przez 1. Jest tak samo, jakbyś od razu napisał 1. (Który w tym przypadku jest to dosłowne int ...)

Edit włączyć się do dyskusji w komentarzach:
Jeśli (lub ktoś inny z dostępem do kodu) zmienia #define LOGIC_ONE 1 do #define LOGIC_ONE "1" to zmienić jego zachowanie w programie i staje się literalnym.

Edit:
Ponieważ ten post dostał większą uwagę, niż się spodziewałem, myślałem dodać odniesień do C++ 14 Standard dla tych ciekawy:

2.2 Fazy tłumaczenia [lex.phases]
(...) 4. Wykonuje się instrukcje przetwarzania wstępnego, wywołania makr są rozszerzane, a _Pragma jednoargumentowe wyrażenia operatora są wykonywane. (...) Wszystkie dyrektywy dotyczące przetwarzania wstępnego są następnie usuwane.
(...)
7. Znaki odstępu od białych znaków nie są już znaczące. Każdy token przetwarzania wstępnego jest konwertowany na token. (2.6). Wynikowe tokeny są analizowane pod względem składni i semantyczności i tłumaczone jako jednostka tłumaczeniowa.

Makra zostały wymienione w fazie 4 i już nie występują. Analiza "syntaktyczna i semantyczna" ma miejsce w fazie 7, gdzie kod zostaje skompilowany ("przetłumaczony").

całkowite literałami podano w

2.13.2 Integer literałach [lex.icon]
(...)
całkowita dosłownym jest ciągiem znaków, który nie ma okresu lub wykładnik część, z opcjonalnym oddzieleniem pojedynczych cudzysłowów, które są ignorowane podczas określania jego wartości. Literał całkowity może mieć prefiks, który określa jego podstawę i sufiks, który określa jego typ.
(...)

Tabela 5 - rodzaje literałach całkowitą

Suffix | Decimal literal  | Binary, octal, or hexadecimal literal 
----------------------------------------------------------------------------- 
none   | int     | int 
      | long int    | unsigned int 
      | long long int   | long int 
      |      | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
u or U  | unsigned int   | unsigned int 
      | unsigned long int  | unsigned long int 
      | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
l or L  | long int    | long int 
      | long long int   | unsigned long int 
      |      | long long int 
      |      | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U | unsigned long int  | unsigned long int 
and l or L | unsigned long long int | unsigned long long int 
----------------------------------------------------------------------------- 
ll or LL  | long long int   | long long int 
             | unsigned long long int 
----------------------------------------------------------------------------- 
Both u or U |unsigned long long int | unsigned long long int 
and ll or LL |      | 

łańcucha znaków są określone w

2.13.5 stałych napisowych [lex.string]
(...)
1 Literał łańcuchowy to sekwencja znaków (jak zdefiniowano w 2.13.3) otoczona podwójnymi cudzysłowami, opcjonalnie z przedrostkiem R, u8, u8R, u, uR, U, UR, L, rLR, jak w " ... ", R" (...) ", u8" ... ", u8R" ** (...) ** ", u" ... ", uR" * ~ (...) * ~ ", U" ... ", UR" zzz (...) zzz ", L" ... "lub LR" (...) ", odpowiednio.
(...)Po fazie translacji 6 literał łańcuchowy, który nie zaczyna się od prefiksu kodowania, jest zwykłym ciągiem literowym i jest inicjowany podanymi znakami.
7 Literał łańcuchowy rozpoczynający się od u8, taki jak u8 "asdf", jest literałem ciągów UTF-8.
8 Zwykłe literały ciągów i literały łańcuchów UTF-8 są również nazywane wąskimi literałami ciągów. Wąskie wyrażenie literowe ma typ "array of n const char", gdzie n jest rozmiarem łańcucha zdefiniowanego poniżej i ma czas przechowywania statycznego (3.7).

+0

, tj. Mogę traktować "LOGIC_ONE" tak, jakby to był "int"? – Noobgineer

+0

@Noobgineer dla bieżącej wartości tak, ale co jeśli ktoś zmieni ją na '" 1 "' –

+2

Możesz potraktować to w jakikolwiek sposób możesz traktować "1" - tak, tak, jego int literał. – Anedar

8

LOGIC_ONE zastępuje się 1 wszędzie, gdzie się pojawi. Jeśli chodzi o kompilator, LOGIC_ONE nie istnieje, po prostu widzi 1. Więc twoje pytanie brzmi "jest 1 int?". Odpowiedź na to -> zależy od tego, gdzie wpisujesz 1

+0

Ok. Nie wiedziałem, czy kompilator szuka "1" czy "LOGIC_ONE". Dziękuję za wyjaśnienie! – Noobgineer

6

Makro jest zamiennikiem tekstu. 1 jest typu constexpr int.

11

Definicja preprocesora nie ma typu - są one po prostu "wklejone" do kodu, w którym się pojawiają. Jeśli na przykład używasz go w instrukcji;

int foo = LOGIC_ONE; 

Następnie zostanie to zinterpretowane jako liczba całkowita. (Kompilator, który działa po preprocesorze, po prostu widzi kod jako int foo = 1;) Można go nawet użyć w grotnym stwierdzeniu, takim jak;

int foo##LOGIC_ONE; 

Następnie utworzysz zmienną foo1. Yuk!

Podjęcie alternatywnego przykładu definicji makra;

#define LOGIC_ONE hello 
int LOGIC_ONE = 5; 
printf("%d\n", hello); 

To całkowicie poprawny, i deklaruje int o nazwie hello, ale pokazuje, że nie ma „typ” dla Definiuje - hello została jedynie podstawionych gdziekolwiek LOGIC_ONE napotkano w kodzie.

Unikaj używania makr preprocesora, chyba że jest to absolutnie konieczne. Profesjonalne standardy kodowania często uniemożliwiają lub znacznie ograniczają korzystanie z preprocesora. Zasadniczo zawsze są lepsze sposoby na robienie rzeczy niż używanie makr. Rozważmy na przykład te alternatywy;

static const int LOGIC_ONE = 1; 
enum { LOGIC_ONE = 1 }; 

Preprocesor to szybki sposób na uczący się dostać w prawdziwym bałagan w C.

+1

Dziękuję za szczegółowe wyjaśnienie. Makra zostały dostarczone jako dodatek do API, którego muszę używać i których nie wolno modyfikować, ale poproszę cię o unikanie makr preprocesora w przyszłych działaniach! – Noobgineer

+0

Myślałem, że wklejenie tokena działa tylko z argumentami makr i nie zostało zastosowane do makr w ogóle? – supercat

+0

Porada przeciwko innym niż bardzo ograniczonym zastosowaniom makr jest 10-krotna w C++ (które to pytanie jest oznaczone). Prawie na pewno jest lepszy sposób na bezpieczną dla tego, co można osiągnąć za pomocą makr. Włączenie pliku, dołączenie strażników i kompilacja warunkowa są pozostałymi pozostałymi elementami wstępnego przetwarzania. – Persixty