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
Editar: este párrafo no es cierto, los argumentos de
int
, incluso cuando se usa como argumento para
sizeof
.
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 a4
porquetrue
yfalse
se definen en<stdbool.h>
como1
y0
respectivamente, por lo que la expresión se expande asizeof(a ? 1 : 0)
que es una expresión entera con tipoint
, que ocupa 4 bytes en su plataforma. Por la misma razón,sizeof(true)
también se evaluaría a4
en su sistema.
Sin embargo, tenga en cuenta que:
-
sizeof(a ? a : a)
también se evalúa a4
porque el operador ternario realiza las promociones enteras en su segundo y tercer operandos si son expresiones enteras. Por supuesto, lo mismo ocurre consizeof(a ? true : false)
ysizeof(a ? (bool)true : (bool)false)
, pero convertir la expresión completa comobool
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
o0
, pero tienen el tipoint
:sizeof(a == a) -> 4
.
Los únicos operadores que mantienen la naturaleza booleana de
a
serían:
-
el operador de coma: tanto
sizeof(a, a)
comosizeof(true, a)
evalúan a1
en tiempo de compilación. -
los operadores de asignación: tanto
sizeof(a = a)
comosizeof(a = true)
tienen un valor de1
. -
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.