以下代码段之间的区别是什么:
{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
double a = 10.154430;
int b = a;
printf("%d", b); //prints 10 (WHY?)
现在,在这两种情况下,我都没有进行显式类型转换,但是我的工作正常..为什么?(int存储双值,它不应该隐式工作)
答案 0 :(得分:3)
请注意,第一种情况相当于printf("%d", (int)a);
从double
到int
的广告投放是特殊情况,它们将浮点转换为整数。
(实际上,大多数其他演员表,例如unsigned long
和short
等各种整数类型之间的演员表,都“保留”了内部表征的大部分内容;在这方面,从积分转换浮动类型或反之亦然,因为涉及一些额外的处理)
您的第二个案例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)==4
和sizeof(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}}。这些仅包括促销小于double
到int
或int
的整数类型,以及将unsigned int
提升为float
。
在double
的特定情况下,当实际参数与相应的字段指令不匹配时,行为未定义。这是你的情况。更一般地说,当UB试图将其变量参数之一解释为与该参数(默认提升的)实际类型不兼容的类型时,UB会发生任何可变函数。