C Macros para crear cadenas

Títulos alternativos (para ayudar a la búsqueda)

  • Convierta un token de preprocesador a una cadena
  • ¿Cómo hacer una cadena de caracteres desde el valor de una macro de C ?

Pregunta original

Me gustaría usar C #define para comstackr cadenas literales en tiempo de comstackción.

La cadena son dominios que cambian por depuración, lanzamiento, etc.

Me gustaría algo como esto:

 #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" 

Pero el preprocesador no evalúa nada dentro de “”

  1. ¿Hay alguna forma de evitar esto?
  2. ¿Es esto incluso una buena idea?

En C, los literales de cadena se concatenan automáticamente. Por ejemplo,

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

s1 y s2 son la misma cadena.

Entonces, para su problema, la respuesta (sin pegar token) es

 #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 

Hay un par de maneras de hacer esto:

  1. Si está tratando solo con literales de cadena, simplemente puede usar cadenas de caracteres: colocar una cadena literal tras otra hace que el comstackdor las concatene.

  2. si puede haber otras cosas además de los literales de cadena implicados (es decir, está creando identificadores nuevos a partir de las macros) utilice el operador de pegado de token de preprocesador ‘ ## ‘. Probablemente también necesite usar el operador de cordaje ‘ # ‘ ‘para convierte tus macros en cadenas literales

Un ejemplo 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 

Y en lo que respecta al operador de pegado de tokens, no creo que la mayoría de las respuestas que sugirieron utilizar el operador de preprocesador de pegado de tokens lo hayan intentado en realidad; puede ser complicado de usar.

Usar la respuesta que a menudo se sugiere dará como resultado un error de comstackción cuando intente utilizar la macro IV_SECURE porque:

 #define IV_SECURE "secure."##IV_DOMAIN 

se expande a:

 "secure"domain.org 

Es posible que desee intentar utilizar el operador ' # `’ ‘stringizing’:

 #define IV_SECURE "secure." #IV_DOMAIN 

Pero eso no funcionará porque solo funciona en macro argumentos, no solo en cualquier macro anterior.

Una cosa a tener en cuenta cuando está usando los operadores de preprocesamiento token-paste (‘##’) o stringizing (‘#’) es que debe usar un nivel adicional de direccionamiento indirecto para que funcionen correctamente en todos los casos.

Si no hace esto y los elementos pasados ​​al operador de pegado de fichas son macros, obtendrá resultados que probablemente no sean los que usted quiere:

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

La salida:

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

Entonces, si usa su IV_DOMAIN original y las macros de IV_DOMAIN de arriba, puede hacer esto para obtener lo que desea:

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

Las cadenas que están juntas son combinadas por el comstackdor de C.

 #define DOMAIN "example.com" #define SUBDOMAIN "test." DOMAIN const char *asCString = SUBDOMAIN; NSString *asNSString = @SUBDOMAIN; 

Intenta usar el operador ##

 #define IV_SECURE secure.##IV_DOMAIN 

Veo muchas respuestas buenas y correctas a su primera pregunta, pero ninguna a su segundo, así que esto es lo siguiente: creo que esta es una idea terrible. ¿Por qué debería tener que reconstruir su software (particularmente la versión de lanzamiento) solo para cambiar el nombre del servidor? Además, ¿cómo sabrá qué versión de su software apunta a qué servidor? Tendrás que crear un mecanismo para verificar en tiempo de ejecución. Si es práctico en su plataforma, le recomiendo que cargue los dominios / URL desde un archivo de configuración. Solo las plataformas integradas más pequeñas pueden no ser “prácticas” para ese propósito 🙂

Lo que necesita son los operadores # y ## y la concatenación automática de cadenas.

El operador # preprocesamiento convierte el parámetro macro en una cadena. El operador ## pega dos tokens (como los parámetros macro) juntos.

La posibilidad que me viene a la mente es

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

que debería cambiar IV_SECURE a

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

que se concatenará automáticamente a “secure.domain.org” (suponiendo que las fases de traducción son las mismas en C que en C ++).

OTRA EDICIÓN: por favor, lea los comentarios, que muestran cómo me he confundido. Tenga en cuenta que tengo mucha experiencia en C, aunque tal vez un toque oxidado. Eliminaría esta respuesta, pero pensé que lo dejaría como un ejemplo de lo fácil que es confundirse con el preprocesador C.

Como otros han notado, usa pegar fichas. También debe tener en cuenta que los nombres de macro les gusta

 __TESTING 

están reservados en C (no sé sobre el Objetivo C) para la implementación; no está permitido usarlos en su propio código. Los nombres reservados son cualquier cosa que contenga guiones bajos dobles y todo lo que comience con un guión bajo y una letra mayúscula.