[C] problemi con #define

FrancoS.1
Salve a tutti,
ho intrapreso lo studio del libro The C puzzle book e mi sono imbattuto in un problema riguardante il comando al preprocessore #define.

Nel libro c'è il seguente pezzo di codice:
#define PR(format, value) printf("value = %format\n", value)


il quale, applicato a questa funzione

#include  <stdio.h>

#define PR(format, value) printf("value = %format\n", value)

int main()
{
 double a;

   a = 100 / 3.;
   PR(g, a);
 return 0;
}


dovrebbe scambiare, durante l'esecuzione delle istruzioni del preprocessore, PR(g,a) con printf("a = %g\n", a).
Evidentemente confondo qualcosa, visto che il risultato che mi appare su schermo è
value = 33.333333ormat

Da quello che posso capire, durante la fase di preprocessore non viene rimpiazzato format con il valore g, il compilatore quindi prende l'istruzione come %f più i caratteri ormat che stampa. Come mai?

Risposte
apatriarca
Dovrei controllare meglio lo standard per verificarlo, ma credo che il problema potrebbe essere la presenza del %. Il preprocessore vede probabilmente la stringa %format e non la riconosce come il suo parametro format. Una possibile soluzione potrebbe essere la seguente:
#define PR(format, value) printf("value = %" # format "\n", value)

Stringhe che appaiono una dopo l'altra nel codice vengono automaticamente concatenate. Per cui # format trasforma g in "g" e a questo punto hai le tre stringe "value = %" "g" "\n" che vengono automaticamente concatenate per formare la stringa di formato che ti interessa.

FrancoS.1
Strano, consultando il libro C: a reference manual di Harbison e Steele leggo che la sintassi del preprocessore è differente dalla sintassi del C; il preprocessore distingue 5 categorie: gli operatori, i separatori, gli identificatori, le parole riservate del linguaggio e le costanti, ma non analizza il testo come fa il compilatore, lo divide in questi tokens e cerca le macro. Non dovrebbe far altro, almeno a quel che ho capito io.

apatriarca
Non capisco cosa trovi di strano. Quella macro non fa altro che usare l'operatore # per convertire quello che viene passato come format in una stringa. Il resto non viene toccato dal preprocessore e viene poi interpretato dal compilatore. È il compilatore C che considera come una singola stringa diverse stringhe scritte una dopo l'altra. Se scrivi insomma "ci" "ao" il compilatore lo interpreterà come "ciao". È utile quando si vuole separare una stringa molto lunga su più righe o quando si vogliono fare cose come questa con il preprocessore.

FrancoS.1
Non mi riferivo alla tua risposta, che anzi mi è stata di aiuto e per cui ti ringrazio, ma al fatto che il preprocessore non si comporti come mi aspetto di fronte al codice %format, prendendo in considerazione solo %f, ho ricontrollato il manuale sopracitato ma ancora non riesco a trovare una risposta.

apatriarca
Il preprocessore vede quella riga come una lista di token. Se il token è uguale all'argomento questo viene modificato, in caso contrario il token rimane invariato. Il problema della tua riga è che una stringa viene vista come un singolo token, per cui il compilatore non cerca l'argomento al suo interno. Il compilatore (il preprocessore se preferisci) vede insomma "printf(, value)" come i token [ "printf", "(", ""value = %format\n"", ",", "value", ")"] e nessuno di questi verrà sostituito. Spero sia chiaro ora.

FrancoS.1
Ho capito, grazie.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.