11

假设在 C 实现上(例如在 x86 C 编译器上)USHRT_MAX = 65535INT_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;否则,它将转换为无符号整数。这些被称为整数提升。(48) 所有其他类型都不受整数提升的影响。

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

但是,根据以下内容,结果是明确定义的,因为涉及无符号操作数的计算不会溢出:

6.2.5-9

有符号整数类型的非负值范围是相应无符号整数类型的子范围,并且每种类型中相同值的表示是相同的。(31)涉及无符号操作数的计算永远不会溢出,因为结果不能用得到的无符号整数类型表示,以比结果类型可以表示的最大值大一的数字为模减少。

product上述语句中的变量是否具有明确定义的值?

编辑:在以下情况下会发生什么?

unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;
4

2 回答 2

4

促销获胜。

USHRT_MAX关于常量等的第 5.2.4.2.1 节说:

下面给出的值应替换为适用于#if预处理指令的常量表达式。此外,除了CHAR_BITand之外MB_LEN_MAX,以下内容应替换为与根据整数提升转换为相应类型的对象的表达式具有相同类型的表达式

所以乘法在ints 上,并且不涉及无符号操作数,毫无疑问,没有一致的方法来实现USHRT_MAX涉及无符号操作数 if 的操作USHRT_MAX < INT_MAX。因此,您有溢出和未定义的行为。

关于添加的问题

编辑:在以下情况下应该发生什么?

unsigned short lhs = USHRT_MAX;
unsigned short rhs = USHRT_MAX;
unsigned short product = lhs * rhs;

那是完全一样的情况。的操作数*受到整数提升,所有类型的值unsigned short都可以通过对和int的值的假设表示为 s ,因此乘法在s 上,并且与指定的值溢出。USHRT_MAXINT_MAXint

您需要将至少一个操作数转换为未提升为的无符号类型,以便int对无符号操作数执行乘法运算。

于 2013-03-27T10:35:54.733 回答
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

很好的收获,顺便说一句。

于 2013-03-27T10:35:22.957 回答