C Macros pour créer des chaînes

autres titres (pour faciliter la recherche)

  • convertissez un jeton préprocesseur en chaîne
  • comment faire une chaîne de caractères à partir d'une macro C valeur?

Question Originale

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

la chaîne de caractères sont des domaines qui changent pour debug, release, etc.

je voudrais quelque chose comme ceci:

#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 cela?
  2. est-ce une bonne idée?
27
demandé sur Brian Tompsett - 汤莱恩 2009-04-28 18:21:01

7 réponses

En C, les chaînes de caractères littérales 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 collage 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
36
répondu Alex B 2009-04-28 15:08:34

il y a plusieurs façons de le faire:

  1. si vous avez affaire à des chaînes littérales, vous pouvez simplement utiliser simplement utiliser des chaînes - placer une chaîne littérale après une autre fait que le compilateur les concaténate.

  2. si il y a peut être d'autres choses que la chaîne de caractères littéraux impliqués (ie., vous créez de nouveaux identificateurs à partir des macros) utilisez le ' ## " préprocesseur opérateur. Vous aurez probablement aussi besoin d'utiliser l'opérateur de string ' # '" pour transformer 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 jeton, Je ne pense pas que la plupart des réponses qui suggéraient d'utiliser l'opérateur de préprocesseur de collage de jeton ont réellement essayé - il peut être difficile à utiliser.

en utilisant la réponse qui est souvent suggéré résultera en une erreur de compilateur lorsque vous essayez d'utiliser la macro IV_SECURE , parce que:

#define IV_SECURE "secure."##IV_DOMAIN

se développe en:

"secure"domain.org

vous pourriez essayer d'utiliser l'opérateur" 1519100920 ` # " 'stringizing':

#define IV_SECURE "secure." #IV_DOMAIN

mais cela ne marchera pas car cela ne fonctionne que sur les Macro arguments - pas n'importe quelle macro ancienne.

une chose à savoir quand vous utilisez le token-paste ('##') ou stringizing ('#') prétraitement des opérateurs est que vous devez utiliser un niveau supplémentaire d'indirection pour eux de travailler correctement dans tous les cas.

si vous ne le faites pas et que les éléments passés à l'opérateur de collage sont des macros eux-mêmes, vous obtiendrez des résultats qui ne sont probablement pas ce que vous voulez:

#include <stdio.h>

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

La sortie:

buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)

desired result:
function_name21

donc en utilisant votre "1519110920 original" définit et les macros utilty de ci-dessus, vous pourriez 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)
22
répondu Michael Burr 2009-04-28 15:00:41
Les chaînes

qui se suivent ensemble sont combinées par le compilateur C.

#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
const char *asCString = SUBDOMAIN;
NSString *asNSString = @SUBDOMAIN;
8
répondu rpetrich 2009-04-28 14:31:43

je vois beaucoup de bonnes et bonnes réponses à votre première question, mais aucune à votre seconde, donc voici ce: je pense que c'est une idée terrible. Pourquoi devez-vous recompiler votre logiciel (en particulier la version release) juste pour changer le nom du serveur? En outre, comment saurez-vous quelle version de votre logiciel pointe sur quel serveur? Vous devrez construire un mécanisme pour vérifier à l'exécution. Si c'est pratique sur votre plate-forme, je vous recommande de charger les domaines/URLs à partir d'une configuration fichier. Seule la plus petite des plateformes embarquées ne peut pas être "pratique":)

7
répondu rmeador 2009-04-28 14:40:04

essayez d'utiliser l'opérateur # #

#define IV_SECURE secure.##IV_DOMAIN
6
répondu JaredPar 2009-04-28 14:23:26

ce dont vous avez besoin sont les opérateurs # et##, et la concaténation automatique des chaînes de caractères.

l'opérateur de prétraitement # transforme le paramètre macro en chaîne. L'opérateur # # remplit deux jetons (comme les paramètres macros) 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 en

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

qui se concaténera automatiquement pour "secure.domain.org" (en supposant que les phases de traduction soient les mêmes en C qu'en C++).

un AUTRE EDIT: s'il vous Plaît, lisez les commentaires, qui montrent comment j'ai réussi à obtenir confus. 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 j'ai pensé que je laisserais comme un exemple de comment il est facile de se confondre par le préprocesseur C.

5
répondu David Thornley 2009-04-28 16:41:57

comme d'autres l'ont noté, utilisez le collage à jeton. Vous devez également être conscient que les noms de macro comme

__TESTING

sont réservés en C (ne sait pas sur L'Objectif 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 soulignement et tout ce qui commence avec un soulignement et une lettre majuscule.

3
répondu 2009-04-28 14:30:26