web-dev-qa-db-fra.com

Stringification d'une macro valeur

J'ai rencontré un problème - j'ai besoin d'utiliser une valeur de macro à la fois comme chaîne et comme entier.

 #define RECORDS_PER_PAGE 10

 /*... */

 #define REQUEST_RECORDS \
      "SELECT Fields FROM Table WHERE Conditions" \
      " OFFSET %d * " #RECORDS_PER_PAGE \
      " LIMIT " #RECORDS_PER_PAGE ";"

 char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];

 /* ...and some more uses of RECORDS_PER_PAGE, elsewhere... */

Cela échoue avec un message sur "Stray #", et même si cela fonctionnait, je suppose que je ferais en sorte que les noms de macro soient stringifiés, pas les valeurs. Bien sûr, je peux fournir les valeurs à la méthode finale ("LIMIT %d ", page*RECORDS_PER_PAGE) mais ce n'est ni joli ni efficace. C'est à des moments comme celui-ci lorsque je souhaite que le préprocesseur ne traite pas les chaînes de manière spéciale et traite leur contenu comme du code normal. Pour l'instant, je l'ai tapoté avec #define RECORDS_PER_PAGE_TXT "10" mais naturellement, je n'en suis pas content.

Comment bien faire les choses?

33
SF.

La macro xstr définie ci-dessous se stringifiera après avoir fait une macro-expansion.

#define xstr(a) str(a)
#define str(a) #a

#define RECORDS_PER_PAGE 10

#define REQUEST_RECORDS \
    "SELECT Fields FROM Table WHERE Conditions" \
    " OFFSET %d * " xstr(RECORDS_PER_PAGE) \
    " LIMIT " xstr(RECORDS_PER_PAGE) ";"
52
#include <stdio.h>

#define RECORDS_PER_PAGE 10

#define TEXTIFY(A) #A

#define _REQUEST_RECORDS(OFFSET, LIMIT)                 \
        "SELECT Fields FROM Table WHERE Conditions"     \
        " OFFSET %d * " TEXTIFY(OFFSET)                 \
        " LIMIT " TEXTIFY(LIMIT) ";"

#define REQUEST_RECORDS _REQUEST_RECORDS(RECORDS_PER_PAGE, RECORDS_PER_PAGE)

int main() {
        printf("%s\n", REQUEST_RECORDS);
        return 0;
}

Les sorties:

SELECT Fields FROM Table WHERE Conditions OFFSET %d * 10 LIMIT 10;

Notez l'indirection vers _REQUEST_RECORDS pour évaluer les arguments avant de les stringifier.

3
Mike Weller

Essayez de double échapper à vos citations

#define RECORDS_PER_PAGE 10
#define MAX_RECORD_LEN 10

 /*... */
#define DOUBLEESCAPE(a) #a
#define ESCAPEQUOTE(a) DOUBLEESCAPE(a)
#define REQUEST_RECORDS \
      "SELECT Fields FROM Table WHERE Conditions" \
      " OFFSET %d * " ESCAPEQUOTE(RECORDS_PER_PAGE)       \
      " LIMIT " ESCAPEQUOTE(RECORDS_PER_PAGE) ";"

 char result_buffer[RECORDS_PER_PAGE][MAX_RECORD_LEN];

int main(){
  char * a = REQUEST_RECORDS;
}

compile pour moi. Le jeton RECORDS_PER_PAGE sera développé par l'appel de macro ESCAPEQUOTE, qui sera ensuite envoyé dans DOUBLEESCAPE pour être cité.

2
Scott Wales