了解printf的隐式转换

时间:2014-11-05 06:58:21

标签: c gcc type-conversion implicit-conversion

C99标准区分隐式和显式类型转换(6.3转换)。我猜,但是当目标类型的精度高于源,并且可以表示其值时,无法找到隐式强制转换。 [这是我认为从INT到DOUBLE发生的事情]。鉴于此,我看下面的例子:

#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);
}

我很惊讶地发现输出:

sizeof(int): 4
sizeof(float): 4
sizeof(double): 8
Little Endian
INT_MIN: -2147483648
INT_MIN as double (or float?): 6.916919e-323

因此,打印的浮点值是非常小的正常正双倍4.9406564584124654×10 ^ -324附近的次正规浮点数。当我为了endianess注释掉两个printf时发生了奇怪的事情,我得到了double的另一个值:

#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);
}

输出:

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
  • 编译器选项其中:gcc -o x x.c -Wall -Wextra -std = c99 --pedantic
  • 是的,有一个警告:
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);
   ^

但我仍然无法理解到底发生了什么。

  • in little endianess我认为MIN_INT为:00 ... 0001和MIN_DBL(Subnormal)为100..00#,从尾数开始,然后是指数,以#作为符号位结束。
  • 这种在int上应用“%e”格式说明符的形式是隐式转换吗?是重新解释转换?

我迷路了,请让我高兴。

2 个答案:

答案 0 :(得分:2)

printf("INT_MIN as double (or float?): %e\n", a);

以上行有问题您无法使用%e打印整数。行为未定义。

你应该使用

printf("INT_MIN as double (or float?): %e\n", (double)a);

double t = a;
printf("INT_MIN as double (or float?): %e\n", t);

Related post:这篇文章解释了如何在printf中使用不正确的打印说明符导致UB。

答案 1 :(得分:0)

va_arg函数的参数没有转换,从语法上来说编译器对这些函数的参数一无所知,所以他不能这样做。现代编译器确实知道解释格式字符串,因此他们能够在发生可疑事情时向您发出警告。当你看到来自gcc的警告时,会发生什么。

更准确地说,有一些针对 narrow 整数类型的促销活动,它们会提升为int,而float会提升为{double 1}}。但这就是所有可能发生的魔法。

总之,始终使用正确的格式说明符。

顺便说一句,size_t表达sizeof表达式%zu正确的{{1}}。