4

考虑这段代码:

uint16_t a = ~ ( uint16_t ) 0;
int16_t  b = ~ ( int16_t ) 0;
printf (
    "%d %d %d %d\n",
    a  == ~ ( uint16_t ) 0,
    a  == ( uint16_t ) ( ~ ( uint16_t ) 0 ),
    b  == ~ ( int16_t ) 0,
    b  == ( int16_t ) ( ~ ( int16_t ) 0 )
);

输出是:

0 1 1 1

GCC 发出警告a == ~ ( uint16_t ) 0

由于数据类型的范围有限,比较总是错误的 [-Wtype-limits]

为什么按位“非”运算符试图返回有符号值?我怎样才能防止这种情况?

4

2 回答 2

9

为什么按位“非”运算符试图返回有符号值?

因为没有运算符适用于小于int; 当用作操作数时,会提升较小的类型(包括uint16_tifint超过 16 位) 。如果原始类型的所有值都可以用 表示,就像它们在这里一样,那么提升将是 to 。intint

我怎样才能防止这种情况?

你不能;这就是语言的工作方式。您必须将运算符的结果转换为您想要的类型,或者像初始化时那样隐式转换,或者使用强制转换a显式转换。请注意,在申请之前您不需要演员表~;但是为了获得最大的可移植性,在执行按位逻辑时应该坚持使用无符号类型:

uint16_t a = ~0u;
printf("%d\n", a == (uint16_t)~0u);  // Should print 1
于 2013-05-11T12:01:47.467 回答
3

符号是我们置于位模式之上的一个概念。按位不 (~) 仅涉及位模式,而不涉及值的符号。不带符号的无符号值的结果是相同的。

话虽如此,看看 C 标准:http ://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf (免费提供草稿版本)。第 6.3.1.4 节,第 51 页:

如果 int 可以表示原始类型的所有值(受宽度限制,对于位域),则该值将转换为 int;否则,它将转换为无符号整数。这些被称为整数促销。(58) 整数提升不会改变所有其他类型。

我认为这意味着,当我们实际对它们进行操作时,char 和 short 类型将被提升为 int(或 unsigned int,具体取决于大小)。这是有道理的,因为我们希望尽可能快地完成操作,因此我们应该针对机器的本机大小。

鉴于此,我们可以看到实际发生的情况。机器将以“int”大小执行所有操作,因为“==”和“~”的操作数都可以放入我假设在您的机器中为 32 位的 int 字段。

现在首先要看的是“a”的值。我们取 0,我们不取 0xFFFFFFFF。我们将其分配给 uint16_t 值并获得 0xFFFF。当我们准备好进行比较时,我们加载 0xFFFF,意识到该值是无符号的,并且零将其扩展到 0x0000FFFF。对于 'b' 的值,除了我们读取 0xFFFF 进行比较之外,一切都是一样的,我们将其扩展为 0xFFFFFFFF。现在针对您的情况:

  1. 注意零给出 0xFFFFFFFF ,与 0x0000FFFF 相比将失败。
  2. 我们取了 0xFFFFFFFF,将其切碎为 0xFFFF,然后将其零扩展为 0x0000FFFF,给出与“a”相同的值。

等等。

于 2013-05-11T12:16:14.937 回答