I faced a problem - I need to use a macro value both as string and as integer.
#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... */
This fails with a message about \"stray #\", and even if it worked, I guess I\'d get the macro names stringified, not the values. Of course I can feed the values to the final method ( \"LIMIT %d \", page*RECORDS_PER_PAGE
) but it\'s neither pretty nor efficient.
It\'s times like this when I wish the preprocessor didn\'t treat strings in a special way and would process their content just like normal code.
For now, I cludged it with #define RECORDS_PER_PAGE_TXT \"10\"
but understandably, I\'m not happy about it.
How to get it right?
The xstr
macro defined below will stringify after doing 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) \";\"
#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;
}
Outputs:
SELECT Fields FROM Table WHERE Conditions OFFSET %d * 10 LIMIT 10;
Note the indirection to _REQUEST_RECORDS to evaluate the arguments before stringifying them.
Try double escaping your quotes
#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;
}
compiles for me. The token RECORDS_PER_PAGE
will be expanded by the ESCAPEQUOTE
macro call, which is then sent into DOUBLEESCAPE
to be quoted.