¿Por qué " sizeof (a? true: false) " dar una salida de cuatro bytes?


Tengo un pequeño fragmento de código sobre el operador sizeof 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 ( CCG):

1
1
4 // Why 4?

Pero aquí,

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

El operador ternario devuelve boolean type y sizeof bool type es 1 byte en C.

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

Author: rsp, 2017-10-30

7 answers

Es porque tienes #include <stdbool.h>. Ese encabezado define macros true y false para ser 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.

 222
Author: Justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-30 08:42:46

Aquí, el operador ternario return boolean type,

OK, hay más que eso!

En C, el resultado de esto la 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 preprocesamiento directriz. Le 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 el evaluación del segundo o tercer operando (el que se evalúe). El segundo operando ser evaluado solo si el primero compara desigual a 0; el tercer operando se evalúa solo si el primero 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 operandos tienen tipo aritmético, el tipo de resultado que sería determinadas por las conversiones aritméticas habituales, si se aplicaban a esos dos operandos, es el tipo de resultado. [....]

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 int main (void) para ser verdaderamente conforme a las normas.

 66
Author: Sourav Ghosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-30 10:33:29

El operador ternario es una pista falsa.

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

Imprime 4 (o lo que sea que sizeof(int) esté en tu plataforma).

El siguiente asume que bool es un sinónimo de char o un tipo similar de tamaño 1, y int es mayor que char.

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

No hay rvalues de tipo bool en C at todo. Cada rvalue se promueve inmediatamente a int, incluso cuando se usa como argumento para sizeof. Editar: este párrafo no es verdadero, los argumentos a sizeof no se promueven a int. Sin embargo, esto no afecta a ninguna de las conclusiones.

 58
Author: n.m.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-31 08:08:00

Respecto al tipo booleano en C

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

Era personalizado para las aplicaciones usar tipos caseros como typedef enum { FALSE, TRUE } BOOL;, que también se reduce a tipos de tamaño int.

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

stdbool.h proporciona cierta compatibilidad con C++. Este encabezado define la macro bool (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 programas de C anteriores. Por lo tanto, true y false se expanden a 1 y 0 en C y su tipo es int. Estas macros no son realmente 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 todavía devuelven un int hasta el día de hoy, a pesar de que C tipo booleano. Mientras que en C++, los operadores lógicos devuelven un bool. Así, 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++.

Respecto 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 del todo.

Hay un punto de secuencia entre la evaluación de la 1ª y la 2ª o 3ª operando. El operador ?: está garantizado para evaluar solo el 2do o el 3er operando, por lo que no puede ejecutar ningún efecto secundario del operando que no se evalúa. Código como true? func1() : func2() no ejecutará func2(). Hasta ahora, todo bien.

Sin embargo, hay una regla especial que indica que el 2do y el 3er operando deben obtener implícitamente el tipo promovido y equilibrado entre sí con las conversiones aritméticas usuales. (Se explican las reglas de promoción de tipo implícito en C aquí). Esto significa que el 2do ó 3er operando siempre será al menos tan grande como un int.

Así que 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 no importa.

Incluso si pudiera volver a escribir la expresión para sizeof(a ? (bool)true : (bool)false) aún así sería devolver el tamaño de un int !

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

 30
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-01 06:29:38

Respuesta rápida:

  • sizeof(a ? true : false) se evalúa como 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 evaluaría a 4 en su sistema.

Tenga en cuenta sin embargo que:

  • sizeof(a ? a : a) también se evalúa a 4 porque el operador ternario realiza las promociones de enteros en su segundo y tercer operandos si estos son expresiones enteras. Lo mismo sucede, por supuesto, para sizeof(a ? true : false) y sizeof(a ? (bool)true : (bool)false), pero lanzar toda la expresión como bool se comporta como se espera: sizeof((bool)(a ? true : false)) -> 1.

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

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

  • El operador de coma: ambos sizeof(a, a) y 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 diferentes semánticas con respecto al tipo bool, valores booleanos true y false, operadores de comparación y el operador ternario: todas estas expresiones sizeof() evalúan a 1 en C++.

 21
Author: chqrlie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-13 14:37:16

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.

 1
Author: u__,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-05 11:42:34

No hay un tipo de datos booleano en C, en cambio las expresiones lógicas evalúan a valores enteros 1 cuando es verdadero de lo contrario 0.

Expresiones condicionales como if, for, while, o c ? a : b espere un entero, si el número es distinto de 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 utilizar para NULL comprobar un puntero, aquí hay un recursivo función que imprime el contenido de una lista de Enlaces individuales.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
 -1
Author: Khaled.K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-03 12:31:01