2008-10-27 14 views
40

Estoy buscando una forma de convertir un token de preprocesador a una cadena.Convertir un token de preprocesador en una cadena

En concreto, he conseguido alguna parte:

#define MAX_LEN 16 

y quiero usarlo para evitar saturación de búfer:

char val[MAX_LEN+1]; // room for \0 
sscanf(buf, "%"MAX_LEN"s", val); 

estoy abierto a otras maneras de lograr lo mismo, pero solo biblioteca estándar.

+0

http://stackoverflow.com/questions/195975/how-to-make-a-char-string-from-ac-macros-value –

+0

Posible duplicado de [C Macros para crear cadenas] (http: // desbordamiento de pila.com/questions/798221/c-macros-to-create-strings) – rjstelling

Respuesta

78

ver http://www.decompile.com/cpp/faq/file_and_line_error_string.htm específicamente:

#define STRINGIFY(x) #x 
#define TOSTRING(x) STRINGIFY(x) 
#define AT __FILE__ ":" TOSTRING(__LINE__) 

por lo que su problema se puede resolver haciendo sscanf(buf, "%" TOSTRING(MAX_LEN) "s", val);

+0

¿por qué poner en cascada 2 macros? ¿No sería suficiente TOSTRING? –

+0

Consulte la respuesta a continuación sobre la stringificación de doble expansión. El preprocesador C/C++ es sucio y feo y creo que sin un estándar. Entonces, ¿por qué requiere dos en lugar de uno? No podría decirlo, porque no quiero hacer la investigación. – Dan

+2

@Daniel Brunner Una sola macro pegará el token, produciendo literalmente '"% "" MAX_LEN ""% "' una segunda macro hace que el token * value * sea pegado, por ejemplo, '" 16 "' porque el 'TOSTRING 'macro hace que el código final sea equivalente a' STRINGIFY (16) '. –

19

Encontré una respuesta en línea.

#define VERSION_MAJOR 4 
#define VERSION_MINOR 47 

#define VERSION_STRING "v" #VERSION_MAJOR "." #VERSION_MINOR 

Lo anterior no funciona, pero es de esperar ilustra lo que me gustaría hacer, es decir, hacer que VERSION_STRING terminan como "v4.47".

para generar la adecuada numérico forma usar algo como

#define VERSION_MAJOR 4 
#define VERSION_MINOR 47 

#define STRINGIZE2(s) #s 
#define STRINGIZE(s) STRINGIZE2(s) 
#define VERSION_STRING "v" STRINGIZE(VERSION_MAJOR) \ 
"." STRINGIZE(VERSION_MINOR) 

#include <stdio.h> 
int main() { 
    printf ("%s\n", VERSION_STRING); 
    return 0; 
} 
+5

"STRINGIZE" suena horrible .. – Blindy

4

Ha sido un tiempo, pero esto debería funcionar:

sscanf(buf, "%" #MAX_LEN "s", val); 

Si no, tendrá que truco "doble expansión":

#define STR1(x) #x 
#define STR(x) STR1(x) 
sscanf(buf, "%" STR(MAX_LEN) "s", val); 
+1

El primero no funcionará; # stringizes argumentos de macro en macro expansiones. El segundo funcionará –

2

Se debe utilizar la doble expansión stringification macro truco. O simplemente tenga un

#define MAX_LEN 16 
#define MAX_LEN_S "16" 

char val[MAX_LEN+1]; 
sscanf(buf, "%"MAX_LEN_S"s", val); 

y manténgalo sincronizado. (Eso es un poco molesto, pero siempre que las definiciones estén una al lado de la otra, probablemente lo recuerde).

¿En realidad, en este caso particular, no sería suficiente strncpy?

strncpy(val, buf, MAX_LEN); 
val[MAX_LEN] = '\0'; 

Si fuera printf, sin embargo, esto sería más fácil:

sprintf(buf, "%.*s", MAX_LEN, val); 
+1

Sí, desearía que el * u otro símbolo estuvieran disponibles para las rutinas escaneadas de escaneo de longitud con un argumento. sprintf en esa forma funciona mejor que strncpy, imo, porque strncpy no terminará la cadena si sobrepasa el búfer, y escribe datos adicionales si la cadena es demasiado corta. – davenpcj

1

Mientras que algunos de los anteriores "trabajo", personalmente lo recomiendo simplemente utilizando una API simple cadena en lugar de la dreck eso viene en libc. Hay una serie de API portátiles, algunas de las cuales también están optimizadas para facilitar la inclusión en su proyecto ... y algunas como ustr tienen una pequeña sobrecarga de espacio y soporte para variables de pila.

Cuestiones relacionadas