2009-04-28 21 views
24

Títulos alternativos (para ayudar a la búsqueda)C macros para crear cadenas

  • convertir un token de preprocesador en una cadena
  • Como hacer un char string del valor de un C de macro?

pregunta original

me gustaría utilizar C#define para construir cadenas literales en tiempo de compilación.

La cadena son dominios que cambian de depuración, etc. liberar

me gustaría un poco de 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 cualquier cosa dentro ""

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

Posible duplicado de [Convertir un token de preprocesador en una cadena] (http://stackoverflow.com/questions/240353/convert-a-preprocessor -token-to-a-string) –

Respuesta

31

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.

Por lo tanto, 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 
6

intente utilizar el operador ##

#define IV_SECURE secure.##IV_DOMAIN 
+1

Esto no resuelve el "" problema. – mouviciel

+0

Creo que el OP estaba preguntando sobre la concatenación de cadenas (#), no sobre el pegado de fichas (##). Sin embargo, no perdoné. La pregunta es un poco ambigua. –

+0

Token pegar ('##') o stringizing ('#') no funcionará sin un poco de cosas adicionales. –

8

cadenas que se siguiente juntos se combinan por el compilador C.

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

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 de que viene a la mente para mí es

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

que debe 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 son iguales 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.

+0

## no pega cadenas, pega tokens. Diferencia sutil pero importante. –

+0

Lamentablemente, la versión de cpp que se ejecuta en mi caja cygwin no comprende el operador # como usted lo describe. – mouviciel

+0

El operador # solo funciona en parámetros de macro. Es decir. #define IV_SECURE (DOMINIO) "seguro". #DOMAIN No es de mucha ayuda en este caso. –

3

Como otros han señalado, el uso pegar token. También debe tener en cuenta que los nombres de macro como

__TESTING 

están reservadas en C (no conocen el objetivo C) para la puesta en práctica - no se le permite utilizarlos 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.

+0

Se supone que el objetivo C es un superconjunto estricto de C, por lo que debe ser un aviso válido. –

19

Hay un par de maneras de hacer esto:

  1. si usted está tratando con sólo literales de cadena, sólo tiene que usar, simplemente utilizar cadenas - colocando una cadena literal tras otro hace que el compilador concatenar .

  2. si puede haber otras cosas que los literales de cadena implicadas (es decir., Que está creando nuevos identificadores de las macros) utilizar el "operador de preprocesador pegar token de ##. Se podría, probablemente, también es necesario utilizar el '#' 'operador stringizing para hacer sus macros en las 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 por lo que el operador va pegando símbolo, no creo que la mayor parte de la responde esa sugerencia El uso del operador del preprocesador de pegado de fichas lo ha intentado, puede ser difícil de usar.

Uso de la respuesta que se sugiere a menudo dará lugar a un error de compilación cuando intenta utilizar la macro IV_SECURE, porque:

#define IV_SECURE "secure."##IV_DOMAIN 

expande a:

"secure"domain.org 

Es posible que desee probar utilizar el ' # `' 'stringizing' operador:

#define IV_SECURE "secure." #IV_DOMAIN 

Pero tha t 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 lo hace, y los artículos pasados ​​al operador de red en pegar las macros son ellos mismos, obtendrá resultados que son probablemente no lo que quiere:

#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 

Así, utilizando sus IV_DOMAIN define originales y las macros UTILTY desde arriba, se puede hacer esto para conseguir lo que quiere:

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

Veo muchas respuestas correctas y buenas a su primera pregunta, pero ninguna a su segundo, así que aquí está 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 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 la más pequeña de las plataformas integradas puede no ser "práctica" para ese propósito :)