C中的显式类型转换

时间:2018-03-10 19:21:57

标签: c casting

以下代码段之间的区别是什么:

  1. {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
  2. double a = 10.154430; int b = a; printf("%d", b); //prints 10 (WHY?)

  3. 现在,在这两种情况下,我都没有进行显式类型转换,但是我的工作正常..为什么?(int存储双值,它不应该隐式工作)

5 个答案:

答案 0 :(得分:3)

请注意,第一种情况相当于printf("%d", (int)a);

doubleint的广告投放是特殊情况,它们浮点转换为整数。

(实际上,大多数其他演员表,例如unsigned longshort等各种整数类型之间的演员表,都“保留”了内部表征的大部分内容;在这方面,从积分转换浮动类型或反之亦然,因为涉及一些额外的处理)

您的第二个案例printf("%d", a)实际上是filterEquals(UB)。您正在使用printf,其参数类型与其控件格式字符串不兼容。 UB可以是undefined behavior

另见worse

答案 1 :(得分:1)

在第一种情况下,存在隐式类型转换。声明

int b = a;       // Implicit conversion. OK

相当于

int b = (int)a;  // Explicit conversion. OK   

(只要类型转换值适合int类型的范围,上述类型转换就可以了。)
而在第二种情况下,您的程序通过不使用double数据类型的正确格式规范来调用未定义的行为。您获得的垃圾值是未定义行为的一种可能结果。

答案 2 :(得分:1)

代码段1和代码段2有所不同,即:
- >在代码片段1中,格式说明符%d 需要Integer类型,并且您引用的是 b ,其类型为 int
- >但是,在代码片段2中,您引用 d 类型为 double 的类型,但格式说明符%d 需要类型 int

答案 3 :(得分:0)

调用printf("%d", a)时,会将以下内容推送到调用堆栈。我们假设sizeof(int)==4sizeof(double)==8

"%d" // address of string literal 
a    // 8 bytes pushed onto stack assuming sizeof(double) is 8
return address of caller

然后调用printf函数本身的跳转。

当printf启动时,它有第一个参数,即已知堆栈偏移量的格式字符串("%d"),但它不知道有多少参数也被压入堆栈。它依赖于格式代码来告诉它如何解释堆栈中的后续字节。

它解析格式字符串并读取%d。然后在看到%d时,它假定被推送的堆栈上的下一个值是一个4字节的整数。然后它从堆栈中读取4个字节,并执行将该内存作为整数打印所需的任何处理。但事实上,它真正打印的是构成浮点值的一半字节。

纯粹以英特尔为例,假设以下代码。

double d = 3.14;
printf("%x\n", d); // push 8-byte double, but print as integer hex
return 0;

打印出来:51eb851f

英特尔处理器存储在内存中的3.14的IEEE浮点表示形式为:1f 85 eb 51 b8 1e 09 40。 double的前4个字节与打印的相同。 (除了反向字节顺序,因为Intel是“小端”)。

答案 4 :(得分:0)

  

现在,在这两种情况下,我都没有进行显式类型转换,但是我的工作正常..为什么?(int存储双值,它不应该隐式工作)

案例1涉及使用简单赋值运算符。操作数满足this operator's constraints,特别是使用案例

  

左操作数具有原子,限定或非限定算术   类型,右边有算术类型

请注意,两个参数的类型不必相同。它们都是算术类型就足够了。在这种情况下,the specified behavior的主要方面是

  

将右操作数的值转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。

(强调补充。)因此,即使没有明确的演员,你也会获得转换。

案例2不同。请注意override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) 的原型:

printf

它是一个可变函数,您可以在可变参数中传递int printf(const char * restrict format, ...); 。现在,当您将参数传递给prototyped函数参数时,您获得与简单赋值完全相同的类型转换,但是对于没有范围内原型的函数的参数以及变量函数的变量参数,您得到{ {3}}。这些仅包括促销小于doubleintint的整数类型,以及将unsigned int提升为float

double的特定情况下,当实际参数与相应的字段指令不匹配时,行为未定义。这是你的情况。更一般地说,当UB试图将其变量参数之一解释为与该参数(默认提升的)实际类型不兼容的类型时,UB会发生任何可变函数。