web-dev-qa-db-fra.com

Convertir un jeton de préprocesseur en chaîne

Je cherche un moyen de convertir un jeton de préprocesseur en chaîne.

Plus précisément, j'ai quelque part:

#define MAX_LEN 16

et je veux l'utiliser pour éviter le dépassement de tampon:

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

Je suis ouvert à d'autres façons d'accomplir la même chose, mais uniquement à la bibliothèque standard.

59
davenpcj

voir http://www.decompile.com/cpp/faq/file_and_line_error_string.htm spécifiquement:

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

afin que votre problème puisse être résolu en faisant sscanf(buf, "%" TOSTRING(MAX_LEN) "s", val);

101
Dan

J'ai trouvé une réponse en ligne.

#define VERSION_MAJOR 4
#define VERSION_MINOR 47

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

Ce qui précède ne fonctionne pas mais, espérons-le, illustre ce que j'aimerais faire, c'est-à-dire que VERSION_STRING devienne "v4.47".

Pour générer la forme numérique appropriée, utilisez quelque chose comme

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

Cela fait un moment, mais cela devrait fonctionner:

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

Sinon, il faudra une astuce "double expansion":

 #define STR1(x)  #x
 #define STR(x)  STR1(x)
 sscanf(buf, "%" STR(MAX_LEN) "s", val);
6
James Curran

Vous devez utiliser l'astuce de macro de stringification à double expansion. Ou tout simplement avoir un

#define MAX_LEN    16
#define MAX_LEN_S "16"

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

et gardez-le synchronisé. (C'est un peu gênant, mais tant que les définitions sont côte à côte, vous vous en souviendrez probablement.)

En fait, dans ce cas particulier, strncpy ne suffirait-il pas?

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

Si c'était printf, ce serait plus simple:

sprintf(buf, "%.*s", MAX_LEN, val);
3
ephemient

Bien que certains des "travaux" ci-dessus, personnellement, je recommanderais simplement d'utiliser une API de chaîne simple au lieu de la dreck qui vient dans libc. Il existe un certain nombre d'API portables, dont certaines sont également optimisées pour faciliter leur inclusion dans votre projet ... et d'autres comme str ont une surcharge d'espace minime et prennent en charge les variables de pile.

1
James Antill