C Macros pour créer des chaînes

Titres alternatifs (pour faciliter la recherche)

  • Convertir un jeton de préprocesseur en chaîne
  • Comment créer une chaîne de caractères à partir de la valeur d’une macro C ?

Question originale

Je voudrais utiliser C #define pour construire des chaînes littérales au moment de la compilation.

La chaîne sont des domaines qui changent pour le débogage, la libération, etc.

Je voudrais quelque chose comme ça:

 #ifdef __TESTING #define IV_DOMAIN domain.org //in house testing #elif __LIVE_TESTING #define IV_DOMAIN test.domain.com //live testing servers #else #define IV_DOMAIN domain.com //production #endif // Sub-Domain #define IV_SECURE "secure.IV_DOMAIN" //secure.domain.org etc #define IV_MOBILE "m.IV_DOMAIN" 

Mais le pré-processeur n’évalue rien dans “”

  1. Y a-t-il un moyen de contourner ceci?
  2. Est-ce même une bonne idée?

En C, les littéraux de chaîne sont concaténés automatiquement. Par exemple,

 const char * s1 = "foo" "bar"; const char * s2 = "foobar"; 

s1 et s2 sont la même chaîne.

Donc, pour votre problème, la réponse (sans coller de jeton) est

 #ifdef __TESTING #define IV_DOMAIN "domain.org" #elif __LIVE_TESTING #define IV_DOMAIN "test.domain.com" #else #define IV_DOMAIN "domain.com" #endif #define IV_SECURE "secure." IV_DOMAIN #define IV_MOBILE "m." IV_DOMAIN 

Il y a plusieurs façons de le faire:

  1. si vous ne traitez que des littéraux de chaîne, vous pouvez simplement utiliser simplement des chaînes – placer un littéral de chaîne après l’autre amène le compilateur à les concaténer.

  2. si d’autres éléments que les littéraux de chaîne sont impliqués (par exemple, si vous créez de nouveaux identifiants à partir des macros), utilisez l’opérateur de collage de jetons de préprocesseur ‘ ## “. transformez vos macros en chaînes littérales.

Un exemple de # 1:

 #ifdef __TESTING #define IV_DOMAIN "domain.org" //in house testing #elif __LIVE_TESTING #define IV_DOMAIN "test.domain.com" //live testing servers #else #define IV_DOMAIN "domain.com" //production #endif // Sub-Domain #define IV_SECURE "secure." IV_DOMAIN //secure.domain.org etc #define IV_MOBILE "m." IV_DOMAIN 

Et en ce qui concerne l’opérateur de collage de jetons, je ne pense pas que la plupart des réponses suggérant d’utiliser l’opérateur de préprocesseur de collage de jetons l’aient réellement essayé – cela peut être délicat à utiliser.

L’utilisation de la réponse souvent suggérée entraîne une erreur de compilation lorsque vous essayez d’utiliser la macro IV_SECURE , pour les raisons suivantes:

 #define IV_SECURE "secure."##IV_DOMAIN 

s’étend à:

 "secure"domain.org 

Vous voudrez peut-être essayer d’utiliser l’opérateur ' #’ ” ssortingngizing ‘:

 #define IV_SECURE "secure." #IV_DOMAIN 

Mais cela ne fonctionnera pas car cela ne fonctionne que sur des arguments de macro – pas n’importe quelle macro ancienne.

Une chose à savoir lorsque vous utilisez les opérateurs de pré-traitement token-paste (‘##’) ou ssortingngizing (‘#’) est que vous devez utiliser un niveau supplémentaire d’indirection pour qu’ils fonctionnent correctement dans tous les cas.

Si vous ne le faites pas et que les éléments transmis à l’opérateur de collage de jetons sont eux-mêmes des macros, vous obtiendrez des résultats qui ne sont probablement pas ce que vous souhaitez:

 #include  #define STRINGIFY2( x) #x #define STRINGIFY(x) STRINGIFY2(x) #define PASTE2( a, b) a##b #define PASTE( a, b) PASTE2( a, b) #define BAD_PASTE(x,y) x##y #define BAD_STRINGIFY(x) #x #define SOME_MACRO function_name int main() { printf( "buggy results:\n"); printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__))); printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__))); printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__))); printf( "\n" "desired result:\n"); printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__))); } 

Le résultat:

 buggy results: SOME_MACRO__LINE__ BAD_PASTE( SOME_MACRO, __LINE__) PASTE( SOME_MACRO, __LINE__) desired result: function_name21 

Donc, en utilisant vos IV_DOMAIN origine IV_DOMAIN et les macros utilty ci-dessus, vous pouvez le faire pour obtenir ce que vous voulez:

 // Sub-Domain #define IV_SECURE "secure." STRINGIFY( IV_DOMAIN) //secure.domain.org etc #define IV_MOBILE "m." STRINGIFY( IV_DOMAIN) 

Les chaînes suivantes sont combinées par le compilateur C.

 #define DOMAIN "example.com" #define SUBDOMAIN "test." DOMAIN const char *asCSsortingng = SUBDOMAIN; NSSsortingng *asNSSsortingng = @SUBDOMAIN; 

Je vois beaucoup de bonnes et de bonnes réponses à votre première question, mais aucune à votre seconde, alors voici ceci: je pense que c’est une idée terrible. Pourquoi devriez-vous reconstruire votre logiciel (en particulier la version finale) simplement pour changer le nom du serveur? Aussi, comment saurez-vous quelle version de votre logiciel pointe sur quel serveur? Vous devrez créer un mécanisme pour vérifier au moment de l’exécution. Si cela est pratique sur votre plate-forme, je vous recommande de charger les domaines / URL à partir d’un fichier de configuration. Seule la plus petite des plates-formes intégrées peut ne pas être “pratique” à cet effet 🙂

Essayez d’utiliser l’opérateur ##

 #define IV_SECURE secure.##IV_DOMAIN 

Ce dont vous avez besoin, ce sont les opérateurs # et ##, ainsi que la concaténation automatique des chaînes.

L’opérateur de prétraitement # transforme le paramètre macro en une chaîne. L’opérateur ## colle deux jetons (tels que des parameters de macro) ensemble.

La possibilité qui me vient à l’esprit est

 #define IV_DOMAIN domain.org #define IV_SECURE(DOMAIN) "secure." #DOMAIN 

qui devrait changer IV_SECURE à

 #define IV_SECURE "secure." "domain.org" 

qui se concaténera automatiquement à “secure.domain.org” (en supposant que les phases de traduction soient les mêmes en C que C ++).

UN AUTRE ÉDIT: S’il vous plaît, veuillez lire les commentaires qui montrent comment j’ai réussi à m’embrouiller. Gardez à l’esprit que je suis très expérimenté en C, bien que peut-être un peu rouillé. Je voudrais supprimer cette réponse, mais je pensais le laisser comme exemple de la facilité avec laquelle le préprocesseur C pourrait confondre.

Comme d’autres l’ont noté, utilisez un collage de jetons. Vous devez également savoir que les noms de macro tels que

 __TESTING 

sont réservés en C (je ne connais pas Objective C) pour la mise en œuvre – vous n’êtes pas autorisé à les utiliser dans votre propre code. Les noms réservés sont tout ce qui contient un double trait de soulignement et tout ce qui commence par un trait de soulignement et une lettre majuscule.