program example cplusplus c macros c-preprocessor stringification

example - C macros para crear cadenas



vector double c++ (7)

Como otros lo han notado, use el pegado de fichas. También debe tener en cuenta que los nombres de macro como

__TESTING

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

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

  • Convertir un token de preprocesador a una cadena
  • ¿Cómo hacer una cadena de caracteres a partir del valor de una macro C ?

Pregunta original

Me gustaría usar C #define para construir cadenas literales en tiempo de compilació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, colocando un literal de cadena detrás de otro hace que el compilador las concatene.

  2. si puede haber otras cosas aparte de los literales de cadena (es decir, si está creando nuevos identificadores a partir de las macros) use el operador de pegado de token del preprocesador '' ## ". Haz 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 usar el operador de preprocesador de pegado de tokens lo hayan intentado realmente, puede ser difícil de usar.

El uso de la respuesta que a menudo se sugiere resultará en un error del compilador cuando intente usar 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 argumentos de macro, no en cualquier macro antigua.

Una cosa que debe tener en cuenta cuando utiliza los operadores de preprocesamiento token-paste (''##'') o de stringizing (''#'') es que tiene que usar un nivel adicional de indirección para que funcionen correctamente en todos los casos.

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

#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 salida:

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

Por lo tanto, al usar sus IV_DOMAIN originales de IV_DOMAIN 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)


Intenta usar el operador ##

#define IV_SECURE secure.##IV_DOMAIN


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

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


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

El operador # preprocesamiento convierte el parámetro macro en una cadena. El operador ## pega dos tokens (como los parámetros de 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 concatenará automáticamente a "secure.domain.org" (suponiendo que las fases de traducción sean las mismas en C que en C ++).

OTRA EDICIÓN: Por favor, lea los comentarios, que muestran cómo he podido confundirme. Tenga en cuenta que tengo mucha experiencia en C, aunque quizás un poco 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.


Veo muchas respuestas buenas y correctas a tu primera pregunta, pero ninguna a tu segunda pregunta, así que aquí tienes esto: 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 construir 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 :)