operator conditionals c++ c boolean ternary-operator

conditionals - conditional operator c++



¿Por qué se usa el operador ternario para definir 1 y 0 en una macro? (7)

Estoy usando un SDK para un proyecto incrustado. 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)

?

Traté de evaluarlo usando

printf("%d", FOO == BAR);

y obtener el resultado 1, por lo que parece que son iguales. ¿Hay alguna razón para escribir el código como lo hicieron?


A veces verás esto en un código muy antiguo , desde antes de que hubiera un estándar C para deletrear que (x > y) evalúa como numérico 1 o 0; algunas CPU prefieren hacer esa evaluación a −1 o 0, y algunos compiladores muy antiguos pueden haber seguido, por lo que algunos programadores sintieron que necesitaban la defensiva adicional.

A veces también verá esto porque las expresiones similares no necesariamente se evalúan como numéricas 1 o 0. Por ejemplo, en

#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)

la expresión & interna se evalúa en 0 o en el valor numérico de F_DO_GRENFELZ , que probablemente no sea 1, entonces el ? 1 : 0 ? 1 : 0 sirve para canonizarlo. Personalmente, creo que es más claro escribir eso como

#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)

pero las personas razonables pueden 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 ? 1 : 0 ? 1 : 0 al final de todos ellos que preocuparse por cuáles realmente lo necesitaban.


En C no importa. Las expresiones booleanas en C tienen el tipo int y un valor que es 0 o 1 , por lo que

ConditionalExpr ? 1 : 0

no tiene efecto.

En C ++, es efectivamente una conversión a int , porque las expresiones condicionales en C ++ tienen el tipo bool .

#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.


Existen herramientas de linting que opinan que el resultado de una comparación es booleano y no puede usarse directamente en aritmética.

No para nombrar nombres o señalar con el dedo, pero PC-lint es una herramienta de linting .

No digo que tengan razón, pero es una posible explicación de por qué el código se escribió así.


Hay un error en el código SDK, y el ternario probablemente fue un error 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'' y& ''c'' no pasará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**

Esta es la razón por la que uno siempre debe paréntesis de macro argumentos 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 ''{''**


Tal vez, al ser un software integrado, daría algunas pistas. Tal vez hay muchas macros escritas usando este estilo, para indicar fácilmente que las líneas ACTI usan lógica directa en lugar de lógica invertida.


Tienes razón, en C es tautólogo. Tanto su condicional ternario particular como (1 > 0) son de tipo int .

Sin embargo, sería importante en C ++, en algunos casos curiosos de esquina (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 tipo bool .

Supongo que el autor ha pensado un poco en esto, con el objetivo de preservar la compatibilidad de C ++.


Una explicación simple es que algunas personas no entienden que una condición devolvería el mismo valor en C o piensan que es más claro escribir ((a>b)?1:0) .

Eso explica por qué algunos también usan construcciones similares en lenguajes con booleanos adecuados, que en sintaxis C sería (a>b)?true:false) .

Esto también explica por qué no debería cambiar innecesariamente esta macro.