假设在C实现上(例如在x86 C编译器上)USHRT_MAX = 65535
和INT_MAX = 2147483647
。那么,以下陈述是否定义明确?
unsigned short product = USHRT_MAX * USHRT_MAX;
根据C99标准中的以下内容,两个操作数都被提升为int
(因为int
可以表示unsigned short
)的所有可能值,因此结果不太好 - 定义,因为会发生溢出(65535 ^ 2 = 4294836225 > 2147483647
),这意味着product
的值没有明确定义:
6.3.1.1-1
如果int可以表示原始类型的所有值,则值为 转换为int;否则,它将转换为unsigned int。 这些被称为整数促销。(48)所有其他类型都是 整数促销没有改变。
48)整数促销仅适用于:通常的一部分 算术转换,到某些参数表达式,到 一元+, - 和〜运算符的操作数,以及两个操作数的操作数 移位运算符,由各自的子条款指定。
但是,根据以下内容,结果是明确定义的,因为涉及无符号操作数的计算不会溢出:
6.2.5-9
有符号整数类型的非负值范围是子范围 相应的无符号整数类型,以及表示形式 每种类型中相同的值是相同的。(31)涉及的计算 无符号操作数永远不会溢出,因为结果不可能 由结果无符号整数类型表示的模数减少 比最大值大1的数字 由结果类型表示。
上述语句中的变量product
是否具有明确定义的值?
编辑:在以下情况下会发生什么?
unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;
答案 0 :(得分:4)
促销获胜。
关于常量USHRT_MAX
等的第5.2.4.2.1节说:
下面给出的值应替换为适用于
#if
预处理指令的常量表达式。此外,除了CHAR_BIT
和MB_LEN_MAX
之外,以下应替换为与根据整数提升转换的对应类型的对象的表达式具有相同类型的表达式< /强>
因此乘法在int
上,并且不涉及无符号操作数,毫无疑问,如果USHRT_MAX
没有符合实现USHRT_MAX < INT_MAX
的方法来获取涉及无符号操作数的操作。因此,您有溢出和未定义的行为。
关于增加的问题
编辑:在下列情况下会发生什么?
unsigned short lhs = USHRT_MAX; unsigned short rhs = USHRT_MAX; unsigned short product = lhs * rhs;
情况完全相同。 *
的操作数受整数提升的约束,unsigned short
类型的所有值都可以通过假设int
和{{1}的值来表示为USHRT_MAX
s因此乘法在INT_MAX
s上,并且指定值溢出。
您需要将至少一个操作数转换为未在oerder中提升为int
的无符号类型,以便对无符号操作数执行乘法。
答案 1 :(得分:1)
你得到UB,因为到应用乘法运算符时,它的操作数已经是有符号整数(因为首先出现int
的促销)。
你可以解决这个问题:
unsigned short product = USHRT_MAX * (unsigned)USHRT_MAX;
证明(unsigned)some_integer
未签名:
#include <stdio.h>
int main(void)
{
printf("1u * (-1) = %f\n", (((unsigned)1) * (-1)) + 0.0);
printf("1 * (-1) = %f\n", (1 * (-1)) + 0.0);
return 0;
}
输出(ideone):
1u * (-1) = 4294967295.000000
1 * (-1) = -1.000000
好抓,顺便说一句。