tipos - Comprender las conversiones implícitas para printf
no se puede convertir implícitamente el tipo double en float (2)
Los argumentos para va_arg
funciones va_arg
no se convierten, sintácticamente el compilador no sabe nada sobre los argumentos para tales funciones, por lo que no puede hacer eso. Sin embargo, los compiladores modernos sí saben interpretar la cadena de formato, por lo que pueden avisarte cuando algo sospechoso está sucediendo. Eso es lo que sucede cuando ves la advertencia de gcc.
Para ser más precisos, hay algunas promociones que se realizan para tipos enteros estrechos , se promueven a int
y para float
que se promociona a double
. Pero eso es todo magia que puede suceder, aquí.
En resumen, use siempre el especificador de formato correcto.
Por cierto, para size_t
partir de tu sizeof
expresiones, la correcta es %zu
.
El estándar C99 distingue entre conversiones de tipo implícito y explícito (6.3 conversiones). Supongo, pero no pude encontrar, que se realizan moldes implícitos, cuando el tipo de objetivo es de mayor precisión que la fuente, y puede representar su valor. [Eso es lo que considero que pasa de INT a DOBLE]. Dado eso, miro el siguiente ejemplo:
#include <stdio.h> // printf
#include <limits.h> // for INT_MIN
#include <stdint.h> // for endianess
#define IS_BIG_ENDIAN (*(uint16_t *)"/0/xff" < 0x100)
int main()
{
printf("sizeof(int): %lu/n", sizeof(int));
printf("sizeof(float): %lu/n", sizeof(float));
printf("sizeof(double): %lu/n", sizeof(double));
printf( IS_BIG_ENDIAN == 1 ? "Big" : "Little" ); printf( " Endian/n" );
int a = INT_MIN;
printf("INT_MIN: %i/n", a);
printf("INT_MIN as double (or float?): %e/n", a);
}
Me sorprendió mucho encontrar ese resultado:
sizeof(int): 4
sizeof(float): 4
sizeof(double): 8
Little Endian
INT_MIN: -2147483648
INT_MIN as double (or float?): 6.916919e-323
Entonces, el valor flotante impreso es un número de coma flotante subnormal cerca del muy mínimo doble positivo subnormal 4,9406564584124654 × 10 ^ -324. Cosas extrañas suceden cuando comento los dos printf por endianess, obtengo otro valor por el doble:
#include <stdio.h> // printf
#include <limits.h> // for INT_MIN
#include <stdint.h> // for endianess
#define IS_BIG_ENDIAN (*(uint16_t *)"/0/xff" < 0x100)
int main()
{
printf("sizeof(int): %lu/n", sizeof(int));
printf("sizeof(float): %lu/n", sizeof(float));
printf("sizeof(double): %lu/n", sizeof(double));
// printf( IS_BIG_ENDIAN == 1 ? "Big" : "Little" ); printf( " Endian/n" );
int a = INT_MIN;
printf("INT_MIN: %i/n", a);
printf("INT_MIN as double (or float?): %e/n", a);
}
salida:
sizeof(int): 4
sizeof(float): 4
sizeof(double): 8
INT_MIN: -2147483648
INT_MIN as double (or float?): 4.940656e-324
- gcc --version: (Ubuntu 4.8.2-19ubuntu1) 4.8.2
- uname: x86_64 GNU / Linux
- opciones del compilador donde: gcc -ox xc -Wall -Wextra-std = c99 --pedantic
- Y sí, allí donde una advertencia:
x.c: In function ‘main’:
x.c:15:3: warning: format ‘%e’ expects argument of type ‘double’, but argument 2
has type ‘int’ [-Wformat=]
printf("INT_MIN as double (or float?): %e/n", a);
^
Pero todavía no puedo entender qué está pasando exactamente.
- en little endianess considero MIN_INT como: 00 ... 0001 y MIN_DBL (Subnormal) como 100..00 #, comenzando con la mantisa, seguido por el exponente y concluyendo con el
#
como un bit de signo. - ¿Es esta forma de aplicar el especificador de formato "% e" en un int, es un elenco implícito ?, ¿una conversión reinterpretada?
Estoy perdido, por favor ilumíname.
printf("INT_MIN as double (or float?): %e/n", a);
La línea superior tiene un problema. No puedes usar %e
para imprimir las entradas. El comportamiento no está definido.
Deberías usar
printf("INT_MIN as double (or float?): %e/n", (double)a);
o
double t = a;
printf("INT_MIN as double (or float?): %e/n", t);
Publicación relacionada : esta publicación explica cómo usar los especificadores de impresión incorrectos en printf puede conducir a UB.