C Macros para crear cadenas

6 minutos de lectura

avatar de usuario
Richard Stelling

Títulos alternativos (para facilitar la búsqueda)

  • Convierta un token de preprocesador en una cadena
  • Cómo hacer una cadena de caracteres a partir de un C el valor de la macro?

Pregunta inicial

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

La cadena son dominios que cambian para 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 siquiera una buena idea?

  • Posible duplicado de Convertir un token de preprocesador en una cadena

    – Ciro Santilli Путлер Капут 六四事

    5 oct 2015 a las 13:33

avatar de usuario
alex b

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

avatar de usuario
miguel rebabas

Hay un par de maneras de hacer esto:

  1. si solo se trata de literales de cadena, simplemente puede usar cadenas: colocar un literal de cadena tras otro hace que el compilador los concatene.

  2. si puede haber otras cosas involucradas además de los literales de cadena (es decir, está creando nuevos identificadores a partir de las macros), use el ‘##” Operador de pegado de token de preprocesador. Probablemente también necesite usar el ‘#‘ ‘operador de cadena para convertir sus 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 probado realmente; puede ser complicado de usar.

Usar la respuesta que a menudo se sugiere resultará en un error del compilador cuando intente usar el IV_SECURE macro, porque:

#define IV_SECURE "secure."##IV_DOMAIN

se expande a:

"secure"domain.org

Es posible que desee intentar utilizar el 'Operador #`’ ‘encadenamiento’:

#define IV_SECURE "secure." #IV_DOMAIN

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

Una cosa que debe tener en cuenta cuando utiliza los operadores de preprocesamiento token-pegar (‘##’) o stringizing (‘#’) es que tiene que 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 tokens son macros en sí mismos, 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

Así que usando tu original IV_DOMAIN define y las macros de utilidad 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)

avatar de usuario
rpetrich

El compilador de C combina las cadenas que siguen juntas.

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

Veo muchas respuestas buenas y correctas a su primera pregunta, pero ninguna a la segunda, así que esto es lo siguiente: creo que 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á 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 🙂

Intenta usar el operador ##

#define IV_SECURE secure.##IV_DOMAIN

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

    – e.James

    28 de abril de 2009 a las 14:38

  • Pegar tokens (‘##’) o encadenar (‘#’) no funcionará sin algunas cosas adicionales.

    – Michael Burr

    28 de abril de 2009 a las 15:01

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

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

La posibilidad que se me ocurre 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 sean las mismas en C que en C++).

OTRA EDICIÓN: Por favor, lea los comentarios, que muestran cómo me las arreglé para confundirme. Tenga en cuenta que tengo mucha experiencia en C, aunque quizás un poco oxidado. Eliminaría esta respuesta, pero pensé en dejarla como un ejemplo de lo fácil que es confundirse con el preprocesador C.

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

    – e.James

    28 de abril de 2009 a las 14:38

  • Pegar tokens (‘##’) o encadenar (‘#’) no funcionará sin algunas cosas adicionales.

    – Michael Burr

    28 de abril de 2009 a las 15:01

Como otros han señalado, use el pegado de tokens. También debe tener en cuenta que nombres de macros como

__TESTING

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

  • Se supone que el objetivo C es un superconjunto estricto de C, por lo que este debería ser un aviso válido.

    – Chris Lutz

    28 de abril de 2009 a las 14:48

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad