textos - convertir una cadena de caracteres a mayusculas en c++
Cómo comparar cadenas en C condicional preprocesador-directivas (8)
Como ya se indicó anteriormente, el preprocesador ISO-C11 no es compatible con la comparación de cadenas. Sin embargo, el problema de asignar una macro con el "valor opuesto" se puede resolver con "pegar token" y "acceso a la tabla". La macro solución de concatenación / stringify simple de Jesse falla con gcc 5.4.0 porque la secuenciación se realiza antes de la evaluación de la concatenación (conforme a ISO C11). Sin embargo, se puede arreglar:
#define P_(user) user ## _VS
#define VS(user) P_ (user)
#define S(U) S_(U)
#define S_(U) #U
#define jack_VS queen
#define queen_VS jack
S (VS (jack))
S (jack)
S (VS (queen))
S (queen)
#define USER jack // jack or queen, your choice
#define USER_VS USER##_VS // jack_VS or queen_VS
S (USER)
S (USER_VS)
La primera línea (macro P_()
) agrega una indirección para permitir que la línea siguiente (macro VS()
) finalice la concatenación antes de la cadena (ver ¿Por qué necesito doble capa de direccionamiento indirecto para las macros? ). Las macros de stringization ( S()
y S_()
) son de Jesse.
La tabla (macros jack_VS
y queen_VS
) que es mucho más fácil de mantener que la construcción if-then-else del OP es de Jesse.
Finalmente, el siguiente bloque de cuatro líneas invoca las macros de estilo de función. El último bloque de cuatro líneas es de la respuesta de Jesse.
Almacenar el código en foo.c
e invocar el preprocesador gcc -nostdinc -E foo.c
produce:
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "foo.c"
# 9 "foo.c"
"queen"
"jack"
"jack"
"queen"
"jack"
"USER_VS"
La salida es como se esperaba. La última línea muestra que la macro USER_VS
no está expandida antes de la stringización.
Tengo que hacer algo como esto en C. Funciona solo si uso un char, pero necesito una cadena. ¿Cómo puedo hacer esto?
#define USER "jack" // jack or queen
#if USER == "jack"
#define USER_VS "queen"
#elif USER == "queen"
#define USER_VS "jack"
#endif
Es simple, creo que solo puedes decir
#define NAME JACK
#if NAME == queen
La respuesta de y de Jesse Chisholm me hizo hacer lo siguiente:
#define QUEEN ''Q''
#define JACK ''J''
#define CHECK_QUEEN(s) (s==QUEEN?1:0)
#define CHECK_JACK(s) (s==JACK?1:0)
#define USER ''Q''
[... later on in code ...]
#if CHECK_QUEEN(USER)
compile_queen_func();
#elif CHECK_JACK(USER)
compile_jack_func();
#elif
#error "unknown user"
#endif
En lugar de #define USER ''Q''
#define USER QUEEN
también debería funcionar, pero no fue probado también funciona y podría ser más fácil de manejar.
Lo siguiente funcionó para mí con clang. Permite lo que aparece como comparación simbólica de valores de macro. #error xxx es solo para ver qué compilador realmente hace. Reemplazar la definición de gato con #define cat (a, b) a ## b rompe las cosas.
#define cat(a,...) cat_impl(a, __VA_ARGS__)
#define cat_impl(a,...) a ## __VA_ARGS__
#define xUSER_jack 0
#define xUSER_queen 1
#define USER_VAL cat(xUSER_,USER)
#define USER jack // jack or queen
#if USER_VAL==xUSER_jack
#error USER=jack
#define USER_VS "queen"
#elif USER_VAL==xUSER_queen
#error USER=queen
#define USER_VS "jack"
#endif
No creo que haya una forma de hacer comparaciones de cadenas de longitud variable por completo en las directivas de preprocesador. Sin embargo, podrías hacer lo siguiente:
#define USER_JACK 1
#define USER_QUEEN 2
#define USER USER_JACK
#if USER == USER_JACK
#define USER_VS USER_QUEEN
#elif USER == USER_QUEEN
#define USER_VS USER_JACK
#endif
O podría refactorizar el código un poco y usar el código C en su lugar.
Si sus cadenas son constantes de tiempo de compilación (como en su caso) puede usar el siguiente truco:
#define USER_JACK strcmp(USER, "jack")
#define USER_QUEEN strcmp(USER, "queen")
#if $USER_JACK == 0
#define USER_VS USER_QUEEN
#elif USER_QUEEN == 0
#define USER_VS USER_JACK
#endif
El compilador puede decir el resultado del strcmp por adelantado y reemplazará el strcmp con su resultado, por lo tanto, le dará un #define que se puede comparar con las directivas del preprocesador. No sé si hay alguna diferencia entre los compiladores / dependencia de las opciones del compilador, pero me funcionó en GCC 4.7.2.
EDITAR: tras una investigación más profunda, parece que se trata de una extensión de cadena de herramientas, no de extensión GCC, así que tenlo en cuenta ...
Use valores numéricos en lugar de cadenas.
Finalmente, para convertir las constantes JACK o QUEEN a una cadena, use los operadores de stringize (y / o tokenize).
[ACTUALIZACIÓN: 2018.05.03]
CAVEAT : No todos los compiladores implementan la especificación C ++ 11 de la misma manera. El código siguiente funciona en el compilador que probé, mientras que muchos comentaristas usaron un compilador diferente.
Citando la respuesta de Shafik Yaghmour en: Calcular la longitud de una cadena C en tiempo de compilación. ¿Es esto realmente un constexto?
No se garantiza que las expresiones constantes se evalúen en tiempo de compilación, solo tenemos una cita no normativa del borrador de la sección estándar de C ++ 5.19 Expresiones constantes que dice esto sin embargo:
[...]> [Nota: las expresiones constantes se pueden evaluar durante la traducción.-nota final]
Esa palabra can
marcar la diferencia en el mundo.
Entonces, YMMV en esta (o cualquiera) respuesta que involucra constexpr
, dependiendo de la interpretación del compilador de la especificación.
[ACTUALIZADO 2016.01.31]
Como a algunos no les gustó mi respuesta anterior porque evitó todo el aspecto de compile time string compare
logrando el objetivo sin necesidad de comparar cadenas, aquí hay una respuesta más detallada.
¡No puedes! No en C98 o C99. Ni siquiera en C11. Ninguna cantidad de manipulación MACRO cambiará esto.
La definición de const-expression
usada en el #if
no permite cadenas.
Permite caracteres, por lo que si te limitas a los personajes, puedes usar esto:
#define JACK ''J''
#define QUEEN ''Q''
#define CHOICE JACK // or QUEEN, your choice
#if ''J'' == CHOICE
#define USER "jack"
#define USER_VS "queen"
#elif ''Q'' == CHOICE
#define USER "queen"
#define USER_VS "jack"
#else
#define USER "anonymous1"
#define USER_VS "anonymous2"
#endif
#pragma message "USER IS " USER
#pragma message "USER_VS IS " USER_VS
¡Usted puede! En C ++ 11. Si define una función auxiliar de tiempo de compilación para la comparación.
// compares two strings in compile time constant fashion
constexpr int c_strcmp( char const* lhs, char const* rhs )
{
return ((''/0'' == lhs[0]) && (''/0'' == rhs[0])) ? 0
: (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0])
: c_strcmp( lhs+1, rhs+1 );
}
// some compilers may require ((int)lhs[0] - (int)rhs[0])
#define JACK "jack"
#define QUEEN "queen"
#define USER JACK // or QUEEN, your choice
#if 0 == c_strcmp( USER, JACK )
#define USER_VS QUEEN
#elif 0 == c_strcmp( USER, QUEEN )
#define USER_VS JACK
#else
#define USER_VS "unknown"
#endif
#pragma message "USER IS " USER
#pragma message "USER_VS IS " USER_VS
Por lo tanto, en última instancia, tendrá que cambiar la forma en que logra su objetivo de elegir los valores de cadena finales para USER
y USER_VS
.
No se puede comparar la cadena de tiempo de compilación en C99, pero puede hacer tiempo de compilación eligiendo cadenas.
Si realmente debe hacer comparaciones de tiempo de compilación, entonces necesita cambiar a C ++ 11 o variantes más nuevas que permitan esa función.
[RESPUESTA ORIGINAL A CONTINUACIÓN]
Tratar:
#define jack_VS queen
#define queen_VS jack
#define USER jack // jack or queen, your choice
#define USER_VS USER##_VS // jack_VS or queen_VS
// stringify usage: S(USER) or S(USER_VS) when you need the string form.
#define S(U) S_(U)
#define S_(U) #U
ACTUALIZACIÓN: pegar token ANSI a veces es menos que obvio. ;-RE
Poner un único #
antes de una macro hace que se cambie a una cadena de su valor, en lugar de su valor simple.
Poner un ##
doble entre dos tokens hace que se concatenen en un solo token.
Entonces, la macro USER_VS
tiene la expansión jack_VS
o queen_VS
, dependiendo de cómo configure USER
.
La macro de stringify S(...)
usa macro indirección para que el valor de la macro nombrada se convierta en una cadena. en lugar del nombre de la macro.
Por lo tanto, USER##_VS
convierte en jack_VS
(o queen_VS
), dependiendo de cómo configure USER
.
Más tarde, cuando la macro stringify se usa como S(USER_VS)
el valor de USER_VS
( jack_VS
en este ejemplo) se pasa al paso indirecto S_(jack_VS)
que convierte su valor ( queen
) en una cadena "queen"
.
Si configura USER
en queen
, el resultado final es la cadena "jack"
.
Para la concatenación de tokens, consulte: https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
Para la conversión de cadenas de tokens, consulte: https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
[ACTUALIZADO 2015.02.15 para corregir un error tipográfico]