#include
using namespace std;
// ---- Nasze dyrektywy ----
#define KWADR(a) ((a) * (a)) // równie dobrze może być - KWADR(c) ((c) * (c))
#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) )
// ---- ---- ---- ---- ----
int main()
{
int b = 10;
cout << "KWADR(b) = " << KWADR(b); // 10 * 10 = 100
cout << "\n\n";
int i = 5;
int x = 10;
cout << MAX(i,x); //cout << 10
}
Jak widzimy, w np. makrodefinicji KWADR jako argument umieściłem zmienną o wartości 10 - KWADR(b). Wszystko pięknie działa. Jednak tutaj już nie
#include
using namespace std;
#define NAZWA(skala) int pomiar ## skala ## ;
int main()
{
int bbb = 56;
NAZWA(bbb);
//int pomiar56;
pomiar56 = 5666;
cout << pomiar56;
}
Jeżeli zmienię argument bbb na 56 to wszystko działa. Jako błąd wyświetla mi się oczywiście, że nigdzie nie było definicji pomiar56… Dlaczego tak się dzieje - ktos wie ?
Ponieważ preprocesor pracuje na tokenach i to przed właściwą kompilacją, wysyłasz mu token bbb i go używa, preprocesor nic nie wie o zmiennych.
W pierwszym przypadku
MAX(i,x) // zamieni się w
( ((i) > (x)) ? (i) : (x) )
Gdybyś ręcznie wpisał ten tekst, który wyprodukuje preprocesor, będzie to poprawne z punktu widzenia tego kodu źródłowego. Natomiast w drugim przykładzie:
NAZWA(bbb); // zamienia się w
int pomiarbbb;
Zostały zwyczajnie połączone tokeny, identycznie jak w pierwszym przykładzie, z tą różnicą, że nie o to Ci chodziło. Musiałbyś bezpośrednio użyć NAZWA(56), wtedy to by działało.
Fakt, zapomniałem o tym, że dyrektywy wykonują się przed kompilacją. Więc czemu w ogóle działa takie podstawianie zmiennych jak w tym 1-szym przykładzie, a 2-gim już nie…
Proszę o wyrozumiałość bo na razie raczkuję dopiero w C++ :oops:
No właśnie chodzi mi o to, że gdybyś ręcznie “zastąpił” preprocesor i sam zmienił MAX(i,x) na ( ((i) > (x)) ? (i) : (x) ) to nadal jest to poprawny kod, zresztą taki sam dostanie kompilator. Kiedy tak samo zastąpisz preprocesor i ręcznie zamienisz NAZWA(bbb) na int pomiarbbb; od razu zauważysz, że nie o to Ci chodziło.
Jeszcze jedna uwaga, jeśli NAZWA(skala) zmieniane jest w “int pomiarskala;” to niepotrzebnie stawiasz średnik po NAZWA() i w efekcie dostajesz dwa średniki w kodzie wyjściowym. W twoim przypadku nic to nie zmienia, ale mimo wszystko warto pamiętać o szczegółach.
W tamtej na górze, kompilator zamieni nazwy zmiennych na wartości. Natomiast w 2 - gim przypadku nie zamieni. Przecież to musiało by być równoznaczne z takim kodem:
int bbb = 56;
// teraz wpisujemy
int pomiarbbb = 100;
// ale kompilator sobie zamieni to i tak na
int pomiar56 = 100;
W rzeczywistości przecież, kompilator nigdy by nie zamienił zmiennej pomiarbbb , na pomiar56 tylko dlatego, że innej zmiennej bbb odpowiada ciąg 56…
No właśnie, musisz pamiętać, że NAZWA(skala) to nie instrukcja , ale ciąg znaków, który kompilator zamieni sobie na inny…
Nie zmieni bo i tak program jest błędem - gdyby wszystko było dobrze to wtedy byłby to błąd i znowu program by się nie skompilował.