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