'cykliczne' dyrektywy #define

0
#define z a
#define y a
#define a y
//W main() mam:
int y=0,z=2;
a=y+z;

Wynik wychodzi taki, że a=2. Nie rozumiem czemu kompilator zgłasza błąd jak dam deklarację int a; Mówi wtedy że redefinicja. To dlaczego kompilator nie mówi tez że redefinicja dla y,z????

0

po uwzględnieniu makr masz coś takiego:

int a=0,a=2;
a=a+a;

Co się oczywiście nie skompiluje.
Zwróć uwagę, że trzeci define jest pod wpływem tego drugiego!

"#define" oznacza zastąp ten symbol takim wyrażeniem/napisem JESZCZE przed kompilacją. Kompilacja następuje dopiero po zinterpretowaniu makra.
Jeśli jesteś początkujący to nie używaj makr, zwłaszcza jeśli masz kłopoty ze zrozumieniem czym właściwie one są.

0

@up:

c:/Documents and Settings/baiji $ gcc def.c -E
# 1 "def.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "def.c"




int main(){
   int y=0,a=2;
   a=y+a;

   return 0;
}

To nie takie proste, kombinujcie dalej.

0

Żeby nie było, że GCC głupieje:

c:/Documents and Settings/baiji $ cl /nologo /E def.c
def.c
#line 1 "def.c"




int main(){
   int y=0,a=2;
   a=y+a;

 return 0;
}

Oba kompilatory (a właściwie preprocesory) zachowują się jak najbardziej prawidłowo...

0

Jak zwykle, jak ja nie napiszę wyjaśnienia to nie ma kto... chociaż może to dobrze, znaczy że ludzie nie (nad)używają preprocesora. Napisałbym wcześniej, ale byłem ciekaw czy się znajdzie ktoś, kto mnie wyręczy.

Owszem, preprocesor robi podstawienie, ale wynik postawienia jest ponownie analizowany i wykonywane są ponowne podstawienia. Jeżeli jednak dany symbol został już raz użyty w danym podstawieniu to nie jest podstawiany ponownie. Z tego wynika, że:

  • zmienna pierwsza: podstawienie 'y' -> 'a' wywołuje podstawienie 'a' -> 'y', 'y' zostało już wcześniej użyte więc na tym podstawianie się zatrzymuje;
  • zmienna druga: podstawienie 'z' -> 'a' wywołuje podstawienie 'a' -> 'y', to zaś 'y' -> 'a', kolejne podstawienie już nie zostaje wykonane ponieważ 'a' zostało w tym łańcuchu podstawień już wykorzystane.

W C++ taka wiedza powinna być zakazana, jak praktycznie cały preprocesor poza #include, w C bywa niezbędna.

0

Jeszcze raz proszę:

#define z a
#define y a
#define a y
//W main() mam:
int y=0,z=2;
a=y+z;

z zostaje zastąpione finalnie jeszcze przed kompilacją symbolem (z->a->y->a) a.
y zostaje zastąpione symbolem (y->a->y) y
a zostaje zastąpione symbolem (a->y->a) a
Czyli jak pojawi sie symbol ten co już był to koniec i własnie ten symbol jest tym finalnym zastąpnikiem?
A czemu dla y,z powyższy kod się kompiluje, a jak dodam deklarację int a to już niestety nie chce się skompilować, bo mówi że redefinicja? To dlaczego nie mówi że dla y jest redefinicja albo dla y i z?

0

Czyli jak pojawi sie symbol ten co już był to koniec i własnie ten symbol jest tym finalnym zastąpnikiem?

Tak, preprocesor nie dopuszcza rekurencji (chociaż tego wprost nikt nigdy nie napisał w standardach C/C++).

A czemu dla y,z powyższy kod się kompiluje, a jak dodam deklarację int a to już niestety nie chce się skompilować, bo mówi że redefinicja? To dlaczego nie mówi że dla y jest redefinicja albo dla y i z?

Dlatego, że wynikiem pierwszej definicji zmiennych są zmienne widziane przez kompilator jako 'a' i 'y' - co doskonale widać na tym co podałem w poprzednich postach i rozpisałem potem.

W drugiej linii zachodzi postawienie 'a' -> 'y', potem 'y' -> 'a', na tym się kończy. Dlaczego wypluwa redefinicję? Zobacz, że 'z' przechodzi w 'a', potem zachodzi proces dla 'a', czyli w praktyce jakby tam od początku było 'a', które będzie przez preprocesor mielone. Jeszcze raz rozpisane, może czytelniej:

#define z a
#define y a
#define a y

[z] z -> a -> y -> a
[y] y -> a -> y
[a]      a -> y -> a

Czyli na wyjściu preprocesora i 'z' i 'a' są przetłumaczone do 'a', dlatego kompilator stwierdza, że już taka zmienna przecież istnieje.

0

To dlaczego kompilator nie stwierdza, że zmienna y tez istnieje??? Czy dlatego że y jest przetłumaczone na siebie samego czyli y???

0

'y' jest tłumaczone na 'y', 'a' i 'z' są tłumaczone na 'a'. Słuchaj, kompilator nie wie jak wyglądał kod przed przepuszczeniem przez preprocesor, na wejście kompilatora idzie wyjście preprocesora.

1 użytkowników online, w tym zalogowanych: 0, gości: 1