【问题标题】:Integer promotion and right shifting整数提升和右移
【发布时间】:2018-08-17 15:01:15
【问题描述】:

考虑到例如 unsigned char 将始终提升为 int,我是否可以假设如果我在转换之前不强制转换为 unsigned char,结果将始终由实现定义?

例如:

unsigned char c = 0x0F;
unsigned int a = c >> 2;

这里 c 在向右移动之前将被提升为 int。因此,移位将由实现定义,具体取决于编译器。

正确的方法是:

unsigned int a = (unsigned char)c >> 2;

我的问题是,这种说法是否属实:

对小于 int 的任何数据类型进行任何转换,如果不转换为无符号类型,将由实现定义?

【问题讨论】:

  • 我不会将 unsigned char 转换为 unsigned char - 嗯。将什么投射到什么?
  • c >> 2(unsigned char)c >> 2 完全相同
  • 不,它永远不会被实现定义,因为将 unsigned char 转换为 int 永远不会产生负 int,并且明确定义了有符号但不是负整数的转移。
  • "unsigned char 将始终被提升为 int" --> 最常见的情况。当unsigned char 范围超过int 范围时,可以提升到unsigned。见@dbush comment

标签: c


【解决方案1】:

结果总是很明确。

有符号类型的右移仅由实现定义如果值为负数。这在C standard 的第 6.5.7p5 节中关于按位移位运算符进行了指定:

E1 >> E2 的结果是 E1 右移 E2 位位置。如果 E1 有 一个无符号类型,或者如果 E1 有一个有符号类型和一个非负值, 结果的值是 E1 / 商的整数部分 2E2。如果 E1 有带符号类型和负值,则结果值 是实现定义的。

该值也不能为负数,因为整数提升会保留被提升值的符号。来自关于整数转换的第 6.3.1.1p3 节:

整数促销保留值,包括符号。正如所讨论的 早些时候,“普通”字符是否被视为已签名是 实现定义。

所以因为保证值是正数,所以右移操作是很好定义的。

【讨论】:

  • 感谢您的回答,在进行整数提升时,我是否需要注意在 msb 中出现 1?
  • 如果原始类型为无符号类型,则否。第 6.3.1.1p2 节指出“如果一个 int 可以表示原始类型的所有值(受宽度限制,对于一个位域),则该值被转换为一个 int;否则,它被转换为一个无符号整数”。因此,如有必要,提升的类型可以是unsigned int
  • 谢谢,整数提升真的让我头疼,我开始想象各种显然不存在的问题。 :)
  • 这正是我想要的行为,但这肯定有税收漏洞的味道
【解决方案2】:

6.5.7p3 在按位移位操作上说:

The integer promotions are performed on each of the operands.

如果您在移位操作的左侧(或右侧,但并不重要)有一个 subint 类型,它将被提升为int

#include <stdio.h>
int main()
{
    http://port70.net/~nsz/c/c11/n1570.html#6.5.7p3
#define TPSTR(X) _Generic(X,unsigned char: "uchar", int: "int")
    unsigned char c = 0x0F;
    printf("%s\n", TPSTR(c>>2));
    printf("%s\n", TPSTR((unsigned char)c>>2));
    printf("%s\n", TPSTR((unsigned char)c>>(unsigned char)2));
}

编译并打印int int int

对有符号整数类型 (int) 的右移结果只有在左操作数为负值时才会被实现定义:

6.5.7p5:

如果 E1 有带符号类型和负值,则结果值为 实现定义。

【讨论】:

  • 这没有回答所提出的问题。
猜你喜欢
  • 2011-03-29
  • 1970-01-01
  • 2011-05-05
  • 1970-01-01
  • 2016-12-15
  • 2012-10-05
  • 2016-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多