Estoy usando un SDK para un proyecto integrado. En este código fuente encontré un código que al menos me pareció peculiar. En muchos lugares del SDK hay un código fuente en este formato:
#define ATCI_IS_LOWER( alpha_char ) ( ( (alpha_char >= ATCI_char_a) && (alpha_char <= ATCI_char_z) ) ? 1 : 0 )
#define ATCI_IS_UPPER( alpha_char ) ( ( (alpha_char >= ATCI_CHAR_A) && (alpha_char <= ATCI_CHAR_Z) ) ? 1 : 0 )
¿El uso del operador ternario aquí hace alguna diferencia?
No es
#define FOO (1 > 0)
lo mismo que
#define BAR ( (1 > 0) ? 1 : 0)
?
Intenté evaluarlo usando
printf("%d", FOO == BAR);
y obtiene el resultado 1, por lo que parece que son iguales. ¿Hay alguna razón para escribir el código como lo hicieron?
c++
c
boolean
ternary-operator
Viktor S
fuente
fuente
(alpha_char)
lugar dealpha_char
, solo para asegurarse de que no se rompa si alguien intenta algo loco comoATCI_IS_LOWER(true || -1)
.boolean
tipo, por lo que el tiempo perdido no contada cambiar horrores comoif (n)
aif (0 != n)
, probablemente, la adición de un elenco dudosa "asegurarse". Estoy seguro de que también supere las desigualdades a prueba de balasif (a < b) ...
. Seguro que se parecía al de Pascalif a < b then ...
, pero sabía que C<
no era unboolean
pero unint
, ¡y unint
podría ser casi cualquier cosa ! El miedo lleva al chapado en oro, el chapado en oro conduce a la paranoia, la paranoia conduce a ... un código como ese.Respuestas:
Tienes razón, en C es tautólogo. Tanto su ternaria en particular condicional y
(1 > 0)
son de tipoint
.Pero sería importante en C ++, sin embargo, en algunos casos curiosos (por ejemplo, como parámetros para funciones sobrecargadas), ya que su expresión condicional ternaria es de tipo
int
, mientras que(1 > 0)
es de tipobool
.Supongo que el autor ha pensado un poco en esto, con miras a preservar la compatibilidad con C ++.
fuente
bool <-> int
conversiones están implícitas en C ++ por §4.7 / 4 del estándar (conversión integral), entonces, ¿qué importancia tendría?foo
, una tomando aconst bool&
la otra tomando aconst int&
. Uno de ellos le paga, el otro formatea su disco duro. Es posible que desee asegurarse de que está llamando a la sobrecarga correcta en ese caso.int
lugar de usar el ternario?Hay herramientas de linting que opinan que el resultado de una comparación es booleano y no se puede usar directamente en aritmética.
No es para nombrar nombres o señalar con el dedo, pero PC-lint es una herramienta muy interesante .
No digo que tengan razón, pero es una posible explicación de por qué el código se escribió así.
fuente
Not to name names or point any fingers,
pero hiciste ambas cosas, lol.A veces verá esto en un código muy antiguo , de antes de que existiera un estándar C para deletrear que se
(x > y)
evalúa como 1 o 0 numérico; algunas CPU prefieren hacer que la evaluación sea -1 o 0 en su lugar, y algunos compiladores muy antiguos pueden haberlo seguido, por lo que algunos programadores sintieron que necesitaban una actitud defensiva adicional.A veces también verá esto porque expresiones similares no necesariamente se evalúan como 1 o 0 numérico. Por ejemplo, en
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)
la
&
expresión interna se evalúa como 0 o el valor numérico deF_DO_GRENFELZ
, que probablemente no es 1, por lo que? 1 : 0
sirve para canonicalizarlo. Personalmente, creo que es más claro escribir eso como#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)
pero la gente razonable puede estar en desacuerdo. Si tuviera un montón de estos en una fila, probando diferentes tipos de expresiones, alguien podría haber decidido que era más fácil de mantener al
? 1 : 0
final de todos ellos que preocuparse por cuáles realmente lo necesitaban.fuente
!!( expr )
para canonizar un booleano, pero admitiré que es confuso si no está familiarizado con él.Hay un error en el código del SDK, y el ternario probablemente fue una torpeza para solucionarlo.
Al ser una macro, los argumentos (alpha_char) pueden ser cualquier expresión y deben estar entre paréntesis porque expresiones como 'A' && 'c' fallarán la prueba.
#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ? 1 : 0 ) std::cout << IS_LOWER('A' && 'c'); **1** std::cout << IS_LOWER('c' && 'A'); **0**
Es por eso que siempre se deben poner entre paréntesis los argumentos macro en la expansión.
Entonces, en su ejemplo (pero con parámetros), ambos tienen errores.
#define FOO(x) (x > 0) #define BAR(x) ((x > 0) ? 1 : 0)
Serían reemplazados más correctamente por
#define BIM(x) ((x) > 0)
@CiaPan Hace un gran punto en el siguiente comentario, que es que usar un parámetro más de una vez conduce a resultados indefinibles. Por ejemplo
#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z')) char ch = 'y'; std::cout << IS_LOWER(ch++); **1** **BUT ch is now '{'**
fuente
IS_LOWER(++ var)
puede incrementarsevar
una o dos veces, además, puede que no note y reconozca minúsculas'z'
sivar
estaba'y'
antes de la llamada a la macro. Es por eso que deben evitarse tales macros, o simplemente reenviar el argumento a una función.En C no importa. Las expresiones booleanas en C tienen un tipo
int
y un valor que es0
o1
, entoncesConditionalExpr ? 1 : 0
no tiene efecto.
En C ++, es efectivamente una conversión a
int
, porque las expresiones condicionales en C ++ tienen tipobool
.#include <stdio.h> #include <stdbool.h> #ifndef __cplusplus #define print_type(X) _Generic(X, int: puts("int"), bool: puts("bool") ); #else template<class T> int print_type(T const& x); template<> int print_type<>(int const& x) { return puts("int"); } template<> int print_type<>(bool const& x) { return puts("bool"); } #endif int main() { print_type(1); print_type(1 > 0); print_type(1 > 0 ? 1 : 0); /*c++ output: int int int cc output: int bool int */ }
También es posible que no se pretendiera ningún efecto, y el autor simplemente pensó que aclaraba el código.
fuente
_Bool
, ahora que C tiene_Bool
y_Generic
. No debería romper mucho código dado que todos los tipos más pequeños se autopromocionanint
en la mayoría de los contextos de todos modos.Una explicación simple es que algunas personas no comprenden que una condición devolvería el mismo valor en C o piensan que es más limpio escribir
((a>b)?1:0)
.Eso explica por qué algunos también usan construcciones similares en lenguajes con booleanos adecuados, que en la sintaxis C sería
(a>b)?true:false)
.Esto también explica por qué no debería cambiar innecesariamente esta macro.
fuente
Quizás, al ser un software integrado, daría algunas pistas. Tal vez haya muchas macros escritas con este estilo, para indicar fácilmente que las líneas ACTI usan lógica directa en lugar de lógica invertida.
fuente