tutorial guia español aprender c boolean sizeof conditional-operator c11

c - guia - solidity español



¿Por qué "sizeof(a? True: false)" da una salida de cuatro bytes? (7)

Tengo un pequeño código sobre el tamaño del operador con el operador ternario:

#include <stdio.h> #include <stdbool.h> int main() { bool a = true; printf("%zu/n", sizeof(bool)); // Ok printf("%zu/n", sizeof(a)); // Ok printf("%zu/n", sizeof(a ? true : false)); // Why 4? return 0; }

Salida ( GCC ):

1 1 4 // Why 4?

Pero aquí,

printf("%zu/n", sizeof(a ? true : false)); // Why 4?

el operador ternario devuelve el tipo boolean y el tamaño del tipo bool es 1 byte en C.

Entonces, ¿por qué sizeof(a ? true : false) da una salida de cuatro bytes?


Aquí, el operador ternario devuelve el tipo boolean ,

OK, hay más que eso!

En C, el resultado de esta operación ternaria es de tipo int . [notas a continuación (1,2)]

Por lo tanto, el resultado es el mismo que la expresión sizeof(int) , en su plataforma.

Nota 1: Citando C11 , capítulo §7.18, Boolean type and values <stdbool.h>

[....] Las tres macros restantes son adecuadas para su uso en #if directivas de preprocesamiento. Son

true

que se expande a la constante entera 1,

false

que se expande a la constante entera 0, [....]

Nota 2: Para el operador condicional, capítulo §6.5.15, ( énfasis mío )

Se evalúa el primer operando; hay un punto de secuencia entre su evaluación y la evaluación del segundo o tercer operando (lo que se evalúe). El segundo operando se evalúa solo si el primero se compara desigual a 0; el tercer operando se evalúa solo si el primero se compara igual a 0; el resultado es el valor del segundo o tercer operando (lo que se evalúe), [...]

y

Si tanto el segundo como el tercer operando tienen tipo aritmético, el tipo de resultado que se determinaría mediante las conversiones aritméticas habituales, si se aplicaran a esos dos operandos. [....]

por lo tanto, el resultado será de tipo entero y, debido al rango de valores, las constantes son precisamente de tipo int .

Dicho esto, un consejo genérico, int main() debería ser mejor int main (void) para ser verdaderamente conforme a los estándares.


Aquí hay un fragmento del cual es lo que se incluye en la fuente

#ifndef __cplusplus #define bool _Bool #define true 1 #define false 0 #else /* __cplusplus */

Allí las macros true y false se declaran como 1 y 0 respectivamente.

sin embargo, en este caso, el tipo es el tipo de las constantes literales. Tanto 0 como 1 son constantes enteras que caben en un int, por lo que su tipo es int.

y el sizeof(int) en su caso es 4.


El operador ternario es un arenque rojo.

printf("%zu/n", sizeof(true));

imprime 4 (o cualquier sizeof(int) está en su plataforma).

Lo siguiente supone que bool es sinónimo de char o un tipo similar de tamaño 1, e int es más grande que char .

La razón por la cual sizeof(true) != sizeof(bool) y sizeof(true) == sizeof(int) es simplemente porque true no es una expresión de tipo bool . Es una expresión de tipo int . Es #define d como 1 en stdbool.h .

No hay valores de tipo bool en C en absoluto. Cada valor de este tipo se promueve inmediatamente a int , incluso cuando se usa como argumento para sizeof . Editar: este párrafo no es cierto, los argumentos de sizeof no se promocionan a int . Sin embargo, esto no afecta a ninguna de las conclusiones.


Es porque tienes #include <stdbool.h> . Ese encabezado define las macros true y false como 1 y 0 , por lo que su declaración se ve así:

printf("%zu/n", sizeof(a ? 1 : 0)); // Why 4?

sizeof(int) es 4 en su plataforma.


No hay ningún tipo de datos booleanos en C, en cambio, las expresiones lógicas evalúan los valores enteros 1 cuando es verdadero, de lo contrario 0 .

Expresiones condicionales como if , for , while o c ? a : b c ? a : b espera un número entero, si el número no es cero se considera true excepto en algunos casos especiales, aquí hay una función de suma recursiva en la que el operador ternario evaluará true hasta que n alcance 0 .

int sum (int n) { return n ? n+sum(n-1) : n ;

También se puede usar para verificar NULL un puntero, aquí hay una función recursiva que imprime el contenido de una Lista Singly-Linked-List.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }


Respuesta rápida:

  • sizeof(a ? true : false) evalúa a 4 porque true y false se definen en <stdbool.h> como 1 y 0 respectivamente, por lo que la expresión se expande a sizeof(a ? 1 : 0) que es una expresión entera con tipo int , que ocupa 4 bytes en su plataforma. Por la misma razón, sizeof(true) también se evaluaría a 4 en su sistema.

Sin embargo, tenga en cuenta que:

  • sizeof(a ? a : a) también se evalúa a 4 porque el operador ternario realiza las promociones enteras en su segundo y tercer operandos si son expresiones enteras. Por supuesto, lo mismo ocurre con sizeof(a ? true : false) y sizeof(a ? (bool)true : (bool)false) , pero convertir la expresión completa como bool comporta como se esperaba: sizeof((bool)(a ? true : false)) -> 1 .

  • También tenga en cuenta que los operadores de comparación evalúan valores booleanos 1 o 0 , pero tienen el tipo int : sizeof(a == a) -> 4 .

Los únicos operadores que mantienen la naturaleza booleana de a serían:

  • el operador de coma: tanto sizeof(a, a) como sizeof(true, a) evalúan a 1 en tiempo de compilación.

  • los operadores de asignación: tanto sizeof(a = a) como sizeof(a = true) tienen un valor de 1 .

  • los operadores de incremento: sizeof(a++) -> 1

Finalmente, todo lo anterior se aplica solo a C: C ++ tiene una semántica diferente con respecto al tipo bool , los valores booleanos true y false , los operadores de comparación y el operador ternario: todas estas expresiones sizeof() evalúan a 1 en C ++.


En cuanto al tipo booleano en C

Un tipo booleano se introdujo bastante tarde en el lenguaje C, en el año 1999. Antes de eso, C no tenía un tipo booleano, sino que se usaba int para todas las expresiones booleanas. Por lo tanto, todos los operadores lógicos como > == ! etc devuelve un int de valor 1 o 0 .

Fue personalizado para las aplicaciones el uso de tipos caseros como typedef enum { FALSE, TRUE } BOOL; , que también se reduce a tipos int -sized.

C ++ tenía un tipo booleano mucho mejor y explícito, bool , que no era mayor de 1 byte. Mientras que los tipos booleanos o expresiones en C terminarían como 4 bytes en el peor de los casos. Se introdujo algún tipo de compatibilidad con C ++ en C con el estándar C99. C luego obtuvo un tipo booleano _Bool y también el encabezado stdbool.h .

stdbool.h proporciona cierta compatibilidad con C ++. Este encabezado define el macro bool (la misma ortografía que la palabra clave C ++) que se expande a _Bool , un tipo que es un tipo entero pequeño, probablemente 1 byte grande. Del mismo modo, el encabezado proporciona dos macros true y false , la misma ortografía que las palabras clave de C ++, pero con compatibilidad con versiones anteriores de los programas de C. Por lo tanto, true y false expanden a 1 y 0 en C y su tipo es int . Estas macros no son en realidad del tipo booleano como lo serían las palabras clave correspondientes de C ++.

Del mismo modo, para fines de compatibilidad con versiones anteriores, los operadores lógicos en C aún devuelven un int hasta el día de hoy, a pesar de que C actualmente tiene un tipo booleano. Mientras que en C ++, los operadores lógicos devuelven un valor bool . Por lo tanto, una expresión como sizeof(a == b) dará el tamaño de un int en C, pero el tamaño de un bool en C ++.

En cuanto al operador condicional ?:

El operador condicional ?: Es un operador extraño con un par de peculiaridades. Es un error común creer que es 100% equivalente a if() { } else {} . No exactamente.

Hay un punto de secuencia entre la evaluación del primer y segundo o tercer operando. Se garantiza que el operador ?: Solo evalúa el 2º o el 3º operando, por lo que no puede ejecutar ningún efecto secundario del operando que no se evalúa. Código como true? func1() : func2() true? func1() : func2() no ejecutará func2() . Hasta ahora tan bueno.

Sin embargo , hay una regla especial que establece que el 2º y 3º operando deben obtener implícitamente el tipo promocionado y equilibrado entre sí con las conversiones aritméticas habituales . ( Las reglas de promoción de tipo implícito en C se explican aquí ). Esto significa que el segundo o tercer operando siempre será al menos tan grande como un int .

Por lo tanto, no importa que true y false sean del tipo int en C porque la expresión siempre daría al menos el tamaño de un int sin importar.

Incluso si reescribiera la expresión en sizeof(a ? (bool)true : (bool)false) , ¡aún devolvería el tamaño de un int !

Esto se debe a la promoción de tipo implícito a través de las conversiones aritméticas habituales.