[英]How can I identify an integer promotion and a demotion in C?
我正在学习 C 和 integer 提升和降级这个词对我来说是新的。 我在 C Standard (C17) 中读到了关于 C 类型转换和 integer 提升的信息,但我不知道如何识别 integer 提升,我对降级一无所知。
例如,如果我有这些代码行:
...
unsigned char x;
int y;
long int z;
int aux; //Auxiliary variable
x = 'c';
y = 1;
z = 2;
aux = x;
aux = y;
aux = z;
aux = x + y; //ZX
aux = y + z;
...
哪里有integer促销? 因为据我所知,在用ZX
注释的代码行中,我有 integer 提升,但仅在那一行,但我不确定; 你能帮我澄清一下吗?
你能举出降级的例子吗? 因为C标准没有明确。
绝对不是我的专长,但让我试试:
unsigned char x;
int y;
long int z;
int aux; //Auxiliar variable
x='c';
y=1;
z=2; // Very subtle promotion here. 2 is an int, and is promoted to long int to fill z.
aux=x; // Value of x, which is a char, is PROMOTED to int, to fill aux
aux=y; // Both left and right sides are int, no promotion/demotion
aux=z; // Z is a long int, is demoted to fill aux.
aux=x+y; // x(char) is PROMOTED for addition, to match other operand y(int)
aux=y+z; // y(int) is promoted to match longer type z(long int). The result(long int) is then demoted to match assignment aux.
我在编程时尽量不要过度依赖提升规则。
Integer promotion 是一个正式的名词 C ,但是不存在所谓的“降级”这个正式甚至非正式的名词。 请查看隐式类型提升规则以了解 integer 转换等级、integer 提升和通常的算术转换。
最接近降级的是“赋值期间的转换”,它可以 go 从较大的类型到较小的类型,反之亦然。 如果操作数的类型不同 (6.5.16.1),这会在赋值期间发生:
在简单赋值(=)中,将右操作数的值转换为赋值表达式的类型,并替换存储在左操作数指定的 object 中的值。
至于实际的转换是如何进行的,参见C17 6.3.1.3。
关于代码中 integer 促销/隐式转换的位置:
x = 'c';
赋值期间的转换,从'c'
的类型int
到unsigned char
。
z = 2;
赋值期间的转换,从2
的类型int
到long
。
aux = x;
赋值期间的转换,从unsigned char
到int
。
aux = z;
赋值期间的转换,从long
到int
。
转换为签名类型涉及实现定义的行为,因此如果较大的值不能适合较小的类型,则可能是一个错误。
aux = x + y;
通常的算术转换,包括 integer 将x
提升为int
。
aux = y + z;
通常的算术转换,将y
变成long
。 然后在分配期间进行转换,转换回int
。 同样,这里可能存在错误。
(最后一个例子中的一些微妙的东西:如果y + z
会导致溢出int
而不是long
的值,溢出实际上不会发生在这里,因为加法之前的long
转换。会有一个转换回int
时的值损失,但仅仅是实现定义的行为而不是未定义的行为溢出。)
术语降级在 C 标准中没有定义,它只在附件 J - 可移植性问题的 C17 标准中使用过一次,仅供参考,不是标准的规范部分。 该短语不是定义,它只是暗示在将值从一种浮点类型转换为另一种浮点类型时可能会发生降级,大概具有较小的域:
附录 J
(资料性的)
便携性问题
1 本附件收集了本国际标准中出现的有关可移植性的一些信息。J.1 未指明的行为
[...]
J.2 未定义的行为
在以下情况下,行为未定义:
[...]
— 将一种真正的浮动类型降级为另一种会产生超出可表示范围的值 (6.3.1.5)。
链接部分未使用该词:
6.3.1.5 真正的浮动类型
1 将实浮点类型的值转换为实浮点类型时,如果被转换的值可以在新类型中准确表示,则它不变。 如果被转换的值在可以表示但不能精确表示的值范围内,则结果是最近的较高或最近的较低可表示值,以实现定义的方式选择。 如果被转换的值超出了可以表示的值范围,则行为未定义。 一些隐式转换的结果可以用比新类型所要求的范围和精度更大的范围和精度来表示(见 6.3.1.8 和 6.8.6.4)。
如仅供参考的附件中所述,降级发生在例如将double
精度值存储到float
变量时,其值不能由float
类型表示。 在一个经典的编程测试中找到了一个典型的案例:
float amount = 0.10; // implicit conversion from double to float
没有像C这样的整数“降级”,但是有升职。 我相信您将晋升和降级与转换混为一谈。
当在表达式中使用小于int
的 integer 类型时,会发生integer 提升,在大多数情况下,它将提升为int
或unsigned int
。 这在C 标准的第 6.3.1.1p2 节中有详细说明:
在可以使用 int 或 unsigned int 的表达式中,可以使用以下内容:
- object 或具有 integer 类型(
int
或unsigned int
除外)的表达式,其 integer 转换等级小于或等于 int 和 unsigned int 的等级。_Bool
、int
、signed int
或unsigned int
类型的位域。如果 int 可以表示原始类型的所有值(受宽度限制,对于位字段),则该值将转换为
int
; 否则,它被转换为unsigned int
。 这些称为integer 促销活动。 integer 促销活动未改变所有其他类型。
这与转换不同,转换发生在任何类型更改为另一种类型时,无论新类型比原始类型大还是小。
现在将其应用于您的示例代码:
x = 'c';
赋值运算符将右操作数转换为左操作数的类型。 字符常量的类型为int
,因此赋值执行从int
到unsigned char
的转换
y = 1;
没有后缀的十进制 integer 常量的类型是int
,所以这里没有转换或提升。
z = 2;
此赋值执行从int
到long int
的转换。
aux = x;
此赋值执行从unsigned char
到int
的转换。
aux = y;
双方有相同的类型,所以没有转换。
aux = z;
此赋值执行从long int
到int
的转换。
aux = x + y; //ZX
首先看+
运算符,左操作数x
首先被提升为int
。 两个操作数现在都具有类型int
,因此没有其他转换,并且x + y
的结果具有类型int
。 对于分配,双方具有相同的类型,因此不应用任何转换
aux = y + z;
首先查看+
运算符,没有提升,因为两个操作数至少与int
一样大。 因为左操作数是int
而右操作数是long int
,所以左操作数被转换为long int
并且y + z
的结果具有long int
类型。 然后将此结果转换为int
以分配给aux
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.