C语言中的显式类型转换

C语言中的显式类型转换,c,casting,C,Casting,以下代码段之间有什么区别: 现在,在这两种情况下,我都没有进行显式类型转换,但case I工作正常..为什么?int存储的是双值,它不应该隐式工作注意,第一种情况相当于printf%d,inta 从double到int的强制转换是一种特殊情况,它们将浮点转换为整数 在实践中,大多数其他类型的转换,例如各种整数类型(如无符号长和短)之间的转换,都保留了内部表示的大部分位;在这方面,从整型转换到浮点型或从浮点型转换到整型是非常特殊的,因为它涉及一些额外的处理 您的第二个案例printf%d,a实际上

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


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

注意,第一种情况相当于printf%d,inta

从double到int的强制转换是一种特殊情况,它们将浮点转换为整数

在实践中,大多数其他类型的转换,例如各种整数类型(如无符号长和短)之间的转换,都保留了内部表示的大部分位;在这方面,从整型转换到浮点型或从浮点型转换到整型是非常特殊的,因为它涉及一些额外的处理

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


另请参见

注意,第一种情况相当于printf%d,inta

从double到int的强制转换是一种特殊情况,它们将浮点转换为整数

在实践中,大多数其他类型的转换,例如各种整数类型(如无符号长和短)之间的转换,都保留了内部表示的大部分位;在这方面,从整型转换到浮点型或从浮点型转换到整型是非常特殊的,因为它涉及一些额外的处理

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


另请参见第一种情况下的隐式类型转换。声明

int b = a;       // Implicit conversion. OK
相当于

int b = (int)a;  // Explicit conversion. OK   
只要类型转换值在int-type范围内,以上类型转换就可以了。
而在第二种情况下,您的程序调用未定义的行为时,并没有为double数据类型使用正确的格式规范。您得到的垃圾值可能是未定义行为的结果之一

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

int b = a;       // Implicit conversion. OK
相当于

int b = (int)a;  // Explicit conversion. OK   
只要类型转换值在int-type范围内,以上类型转换就可以了。
而在第二种情况下,您的程序调用未定义的行为时,并没有为double数据类型使用正确的格式规范。您得到的垃圾值可能是未定义行为的结果之一

代码段1和代码段2有一个区别,即: ->在代码段1中,格式说明符%d需要整数类型,而您引用的是int类型的b。
->但是,在代码段2中,您引用的是类型为double但格式说明符%d要求类型为int的d,代码段1和代码段2存在差异,即: ->在代码段1中,格式说明符%d需要整数类型,而您引用的是int类型的b。 ->但是,在代码段2中,您引用的是类型为double的d,但格式说明符%d需要类型int

调用printf%d时,会将以下内容推送到调用堆栈上。让我们假设sizeofint==4和sizeofdouble==8

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

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

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

仅看一个Intel示例,假设以下代码

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是little endian

调用printf%d,a时,将以下内容推送到调用堆栈上。让我们假设sizeofint==4和sizeofdouble==8

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

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

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

仅看一个Intel示例,假设以下代码

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是little endian

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

案例1涉及使用简单赋值运算符。操作数满足,特别是利用大小写

左操作数具有原子运算、限定运算或非限定运算 类型,右侧为算术类型

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

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

重点补充。因此,即使没有显式强制转换,也会得到转换

案例2则不同。请注意printf的原型:

这是一个变量函数,在变量参数之间传递double。现在,当你把一个参数传递给一个原型函数参数时,你得到的转换和你在简单赋值中得到的完全一样,但是对于没有范围内原型的函数的参数和变量函数的变量参数,你得到的是。这些仅包括将小于int的整数类型升级为int或无符号int,并将浮点升级为double

在printf的特定情况下,当实际参数与相应的field指令不匹配时,行为是未定义的。这是你的案子。更一般地说,当任何变量函数试图将其一个变量参数解释为与该参数的默认实际类型不兼容的类型时,都会出现UB

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

案例1涉及使用简单赋值运算符。操作数满足,特别是利用大小写

左操作数具有原子运算、限定运算或非限定运算 类型,右侧为算术类型

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

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

重点补充。因此,即使没有显式强制转换,也会得到转换

案例2则不同。请注意printf的原型:

这是一个变量函数,在变量参数之间传递double。现在,当你把一个参数传递给一个原型函数参数时,你得到的转换和你在简单赋值中得到的完全一样,但是对于没有范围内原型的函数的参数和变量函数的变量参数,你得到的是。这些仅包括将小于int的整数类型升级为int或无符号int,并将浮点升级为double


在printf的特定情况下,当实际参数与相应的field指令不匹配时,行为是未定义的。这是你的案子。更一般地说,当任何变量函数试图将其一个变量参数解释为与该参数的默认提升实际类型不兼容的类型时,都会出现UB。

在第一种情况下,a的值被截断为小于或等于a的最大整数,这个整数值被分配给b.int存储的是双值,这不应该隐式工作-语言标准不同意你的观点,在第一种情况下,a的值被截断为小于或等于a的最大整数,而这个整数值被分配给b.int存储的是双值,这不应该隐含地起作用——语言标准在这一点上与您不一致
int printf(const char * restrict format, ...);