2010-04-16 53 views
20

Me enfrenté a un problema: necesito usar un valor de macro como cadena y como número entero.Stringification de un valor de macro

#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... */ 

Esta falla con un mensaje sobre "perdida #", e incluso si funcionaba, supongo que me gustaría obtener los nombres de macro Stringified, no los valores. Por supuesto, puedo enviar los valores al método final ("LIMIT %d ", page*RECORDS_PER_PAGE) pero no es bonito ni eficiente. Es en momentos como este cuando deseo que el preprocesador no trate las cadenas de una manera especial y procese su contenido al igual que el código normal. Por ahora, lo hice con #define RECORDS_PER_PAGE_TXT "10", pero comprensiblemente, no estoy contento con eso.

Cómo hacerlo bien?

+2

Preprocesado correctamente para mí en gcc. – kennytm

+0

Ejemplo en kernel de Linux: http://lxr.free-electrons.com/source/include/linux/stringify.h?v=4.7 –

Respuesta

37

La macro xstr que se define a continuación se codificará después de realizar la macroexpansión.

#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) ";" 
+1

¿es este un requisito reciente? No recuerdo que se requirieran tales trucos la última vez que utilicé la stringificación ... – PypeBros

+0

Para una referencia adicional, una descripción adicional de los mecanismos (y matices) de la stringificación (GNU CPP) disponible en http://gcc.gnu.org/onlinedocs /cpp/Stringification.html. –

+1

Enlace de documentación de GCC actualizado: https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing – eresonance

2

tratar de Double escapar sus cotizaciones

#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; 
} 

compila para mí. El token RECORDS_PER_PAGE se expandirá mediante la macro llamada ESCAPEQUOTE, que luego se enviará al DOUBLEESCAPE para ser cotizado.

+0

Pero no sustituye los valores correctos porque los contenidos de # no se evalúan primero . –

+0

@Mike Olvidó el doble escape –

1
#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; 
} 

Salidas:

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

Nota del direccionamiento indirecto a _REQUEST_RECORDS para evaluar los argumentos antes stringifying ellos.

Cuestiones relacionadas