C preprocessor
Giorgos Keramidas
keramida at ceid.upatras.gr
Wed Nov 3 10:48:16 EET 2010
On Tue, 02 Nov 2010 23:19:14 +0200, Houtouridis Christos <hoo2.ch.pub at gmail.com> wrote:
> Για να μην 'βγω τελείως off-topic, μιας και η λίστα είναι για χρήστες
> linux θα σας πω το εξής, που αν θέλετε το πιστεύετε. Τα παρακάτω τα
> δοκιμάζω σε ένα μηχάνημα με debian squeeze.
>
> Έστω:
> --------------
>
> typedef struct
> {
> int a;
> int b;
> }mytype_t;
>
> θέλουμε ένα macro fun που να παίρνει όλο το mytype_t αλλά να δουλεύει με
> τα .a kai .b
> Κάτι δλδ σαν το παρακάτω που ΔΕΝ δουλεύει.
>
> #define fun(A,B) \
> do{ \
> A##.a = 5 + B##.a; \
> A##.b = -5 + B##.b; \
> }while (0)
>
> Ώστε να μπορείς να την καλέσεις κάπως έτσι
>
> void main(void)
> {
> mytype_t mpla, mplo={6,7};
> fun(mpla, mplo); //(1)
> }
> Όμως ο πρεπρο(φ)εσσορας βγάζει για την γραμμή (1) αυτό:
> do{mpla a = 5 + mplo a;mpla b = -5 + mplo b; }while (0);
> ^ ^ ^
> | | |
Η λύση είναι πιο απλή από το ## concatenation operator. Απλά δεν
ασχολείσαι καν με το κενό:
keramida at kobe:~$ cat -n foo.c
1 #define fibostruct(a, b) \
2 do { \
3 (a).foo = (b).foo; \
4 (a).bar = (b).foo + (b).bar; \
5 } while (0)
6
7 fibostruct(koko, lala);
keramida at kobe:~$ cpp foo.c | cat -n
1 # 1 "foo.c"
2 # 1 "<built-in>"
3 # 1 "<command-line>"
4 # 1 "foo.c"
5
6
7
8
9
10
11 do { (koko).foo = (lala).foo; (koko).bar = (lala).foo + (lala).bar; } while (0);
keramida at kobe:~$
Σημείωση 1
----------
Ακόμη και να ΕΙΧΕ κενό πριν ή μετά το struct member reference, δεν
πειράζει όμως. Δες π.χ. το παρακάτω πρόγραμμα:
keramida at kobe:~$ cat -n lala.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 struct foo {
5 int a;
6 int b;
7 };
8
9 int
10 main(void)
11 {
12 struct foo x;
13
14 x . a = 3;
15 x . b = 4;
16 printf("{ a = %d, b = %d }\n", x . a, x . b);
17 return 0;
18 }
keramida at kobe:~$ cc -W -Wall lala.c
keramida at kobe:~$ ./a.out
{ a = 3, b = 4 }
keramida at kobe:~$
Τον compiler δεν τον ενοχλεί *καθόλου* να υπάρχει κενό πριν ή μετά το
'.' ενός struct member reference. Αυτό συμβαίνει γιατί το expression:
foo.x = 3;
Το "σπάει" στη διάρκεια της λεκτικής ανάλυσης σε tokens της μορφής:
<symbol 'foo'> <struct-dot> <symbol 'x'> <equal sign> <symbol '3'> <semicolon>
Κι αφού το σπάσει στο πιο αναλυτικό σετ από λεκτικά σύμβολα που μπορεί,
ΤΟΤΕ ασχολείται με το expression ως συντακτική οντότητα. Στο επίπεδο
που γίνεται η ανάλυση του expression ως valid ή όχι, το κενό που είχες
πριν ή μετά το struct-dot απλά δεν υπάρχει πλέον ;-)
Σημείωση 2
----------
Γενικά το ## operator χρειάζεται μόνο όταν θέλεις να ενώσεις symbol
*names* και το ίδιο το ## operator πρέπει να έχει *πάντα* κενά τριγύρω
του, τα οποία είναι _υποχρεωμένος_ να τα _αφαιρέσει_ κατά το symbol-name
concatenation ο preprocessor.
Για παράδειγμα:
keramida at kobe:~$ cat -n bar.c
1 #define DEFTEST(test_name) \
2 int test_case_ ## test_name (void)
3
4 DEFTEST(KOKO_LALA);
5 DEFTEST(FOO_BAR);
keramida at kobe:~$ cpp bar.c | cat -n
1 # 1 "bar.c"
2 # 1 "<built-in>"
3 # 1 "<command-line>"
4 # 1 "bar.c"
5
6
7
8 int test_case_KOKO_LALA (void);
9 int test_case_FOO_BAR (void);
keramida at kobe:~$
More information about the Linux-greek-users
mailing list