C99标准 类型转换(算术操作数篇)(中文)

6.3 转换

一些运算符将操作数值从一种类型自动转换为另一种类型。此子条款指定此类隐式转换所需的结果,以及那些由强制转换操作(cast operation)(显式转换)产生的结果。6.3.1.8中的列表总结了大多数普通操作符执行的转换;在6.5中对每个操作符进行了讨论并对其进行了必要的补充。

将操作数值转换为兼容类型不会对值或表示形式造成更改
【译者注】 转换是临时的,不会改变原类型。例如将一个 char 型变量 a 的值赋给 int 型变量 b ,则会将 a 的值提升为 int 型然后再赋给 b,但变量 a 的类型依然是 char,变量 a 中储存的值也仍然是 char 型。

提前引用: 强制转换操作符(6.5.4)。

6.3.1 算术操作数

6.3.1.1 布尔值、字符和整数
整数转换秩

每种整数类型都有一个整数转换秩(integer conversion rank),定义如下:

  • 任何两个有符号整数类型都不应具有相同的秩,即使它们具有相同的表示形式。
  • 有符号整数类型的秩应大于精度较低的任何有符号整数类型的秩。
  • long long int 的秩应该大于 long int 的秩,而 long int 的秩应该大于 int 的秩,而 int 的秩应该大于 short int的秩 ,而 short int 的秩应该大于 signed char 的秩。
  • 任何无符号整数类型的秩应该等于相应的有符号整数类型的秩(如果有的话)。
  • 任何标准整数类型的秩应该大于具有相同宽度的任何扩展整数类型的秩。
  • char 的秩应该等于 signed char 和 unsigned char 的秩。
  • _Bool 的秩应该小于所有其他标准整数类型的秩。
  • 任何枚举类型的秩应等于兼容整数类型的秩(见6.7.2.2)。
  • 任何扩展有符号整数类型相对于另一个具有相同精度的扩展有符号整数类型的秩是由实现定义的,但仍然受确定整数转换秩的其他规则的约束。
  • 对于所有整数类型 T1、T2 和 T3,如果 T1 的秩大于 T2,而 T2 的秩大于 T3,则 T1 的秩大于 T3。
整型提升

下面的表达式可以在任何可以使用 int 或 unsigned int 的表达式中使用:

  • 整数类型的对象或表达式,其整数转换秩小于 int 和 unsigned int 的秩。
  • 类型为 _Bool、int、signed int 或 unsigned int 的位域。

如果 int 类型可以表示原始类型的所有值,则将该值转换为 int 类型;否则,它将被转换为 unsigned int。这些被称为整型提升[1]。所有其他类型都不受整数提升的影响。

[1] 整型提升仅应用于:作为普通算术转换的一部分,应用于某些参数表达式,应用于单目运算符 +、- 和 ~ 的操作数,以及移位运算符的两个操作数(由它们各自的子条款指定)。

【译者注】请读者注意!这里的单目运算符 +、-,既不同于单目运算符 ++、- -,也不同于四则运算中的 +、- 。单目运算符 +、- 用于对操作数进行整型提升,假设有 char num = 1; 则 (+)num 运算将 num 的值提升为 int 型。请不要将这三种运算符混淆。

整型提升保持其中的符号值。正如前面所讨论的,是否将“普通” char 作为有符号处理是由实现定义的
【译者注】例如 keil C51 中就将 char 作为无符号处理。

提前引用:枚举说明符(6.7.2.2)、结构体和联合说明符(6.7.2.1)。

6.3.1.2 布尔类型

当任何标量值被转换为 _Bool 时,如果该值比较等于 0,则结果为 0;否则,结果为1。

6.3.1.3 有符号整数和无符号整数

当具有整型类型的值被转换为 _Bool 以外的另一种整型时,如果该值可以用新类型表示,则该值不变。

否则,如果新类型是无符号的,则通过反复加或减比新类型可以表示的最大值大 1 的值来转换值,直到该值处于新类型的范围内[2]
【译者注】 这相当于高位宽类型转低位宽类型时,截取低位;低位宽类型转高位宽类型时,对带符号值进行符号扩展和对无符号值进行0填充。

否则,新类型是有符号的,不能用它来表示值;要么结果是实现定义的,要么抛出一个实现定义的信号。

[2] 这些规则描述的是数学值的算术运算,而不是给定类型表达式的值。

6.3.1.4 浮点数和整数

当一个浮点型的有限值被转换为 _Bool 以外的整数类型时,小数部分将被丢弃(即,该值被截断为零)。如果整型类型不能表示整数部分的值,则未定义行为[3]

当一个整型的值被转换为一个浮点型时,如果被转换的值可以用新类型精确地表示,那么它是不变的。如果要转换的值在可以表示但不能精确表示的值范围内,则结果是最接近的较高值或较低值,以实现定义的方式选择。如果要转换的值不在可以表示的值范围内,则该行为未定义。

[3] The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).。

6.3.1.5 浮点类型(Real floating types)

当 float 提升为 double 或 long double,或者 double 提升为 long double 时,它的值不会改变。

当 double 降级为 float,long double 降级为 double 或者 float,或者一个比其语义类型(见6.3.1.8)要求的精度和范围更高的值被显式转换为其语义类型时,如果被转换的值可以用新类型精确地表示,那么它是不变的。如果要转换的值在可以表示但不能精确表示的值范围内,则结果要么是最接近的更高值,要么是最接近的更低值,以实现定义的方式选择。如果要转换的值不在可以表示的值范围内,则该行为未定义。

6.3.1.6 复数类型

当将一个复数类型的值转换为另一个复数类型时,实部和虚部都遵循对应实类型的转换规则。

6.3.1.7 实数和复数

当一个实数类型的值被转换为复数类型时,复数结果值的实部由相应实数类型的转换规则决定,复数结果值的虚部为正零或无符号零。

当将复数类型的值转换为实数类型时,丢弃复数的虚部,并根据对应实数类型的转换规则转换实数部分的值。

6.3.1.8 普通算术类型转换

许多期望算术类型操作数的运算符以类似的方式进行转换并产生结果类型。目的是为操作数和结果确定一个公共类型(common real type)。对于指定的操作数,在不改变类型域(type domain)的情况下,将每个操作数转换为其对应的类型的公共类型。除非明确声明,公共类型也是结果对应的类型,如果操作数相同,其类型域是操作数的类型域,否则为复数。这种模式称为普通算术转换(usual arithmetic conversions):

首先,如果任一操作数对应的实类型为 long double,则另一个操作数将在不改变类型域的情况下转换为其对应的实类型 long double。

否则,如果其中一个操作数对应的实类型为 double,另一个操作数将在不改变类型域的情况下转换为其对应的实类型 double。

否则,如果其中一个操作数的对应实数类型为 float,则另一个操作数将在不改变类型域的情况下转换为其对应实数类型 float[4]

否则,对两个操作数都执行整数提升。然后对提升后的操作数应用以下规则:

如果两个操作数具有相同的类型,则不需要进一步转换。

否则,如果两个操作数都是有符号整数类型或都是无符号整数类型,则整数转换秩较小的操作数类型被转换为秩较大的操作数类型。

否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则有符号整数类型的操作数被转换为无符号整数类型的操作数的类型。

否则,如果有符号整型的操作数类型可以表示无符号整型操作数类型的所有值,则将无符号整型操作数转换为有符号整型操作数的类型。

否则,两个操作数都被转换为无符号整型,对应于有符号整型操作数的类型[5]

[4] 例如,一个double _Complex和一个float相加只需要将float操作数转换为double(并产生一个double _Complex结果)

[5] 强制转换和赋值操作符仍然需要执行6.3.1.4和6.3.1.5中所述的指定转换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值