c - 无符号类型和更大的有符号类型之间的隐式转换行为不一致

标签 c c99 implicit-conversion c89 integer-promotion

考虑以下示例:

#include <stdio.h>

int main(void)
{
    unsigned char a  = 15; /* one byte */
    unsigned short b = 15; /* two bytes */
    unsigned int c   = 15; /* four bytes */

    long x = -a; /* eight bytes */
    printf("%ld\n", x);

    x = -b;
    printf("%ld\n", x);

    x = -c;
    printf("%ld\n", x);

    return 0;
}

为了编译,我使用的是 GCC 4.4.7(它没有给我任何警告):

gcc -g -std=c99 -pedantic-errors -Wall -W check.c

我的结果是:

-15
-15
4294967281

问题是为什么 unsigned charunsigned short 值都被正确“传播”到(signed)long,而 unsigned int 不是吗?有没有这方面的引用或规则?

以下是 gdb 的结果(单词按小端顺序排列):

(gdb) x/2w &x
0x7fffffffe168: 11111111111111111111111111110001    11111111111111111111111111111111 

(gdb) x/2w &x
0x7fffffffe168: 11111111111111111111111111110001    00000000000000000000000000000000

最佳答案

这是由于整数提升应用于操作数的方式以及一元减法的结果具有相同类型的要求。这在 6.5.3.3 一元算术运算符 部分中有所介绍,并说(强调我的前进):

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

和 c99 标准草案部分 6.3 Conversions 中涵盖的整数提升并说:

if an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.

前两种情况,提升为int,结果为int。在 unsigned int 的情况下,不需要提升,但结果将需要转换回 unsigned int

-15 使用 6.3.1.3 部分中规定的规则转换为 unsigned int 有符号和无符号整数 上面写着:

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.49)

所以我们以 -15 + (UMAX + 1) 结束,这导致 UMAX - 14 导致一个大的无符号值。这就是为什么有时您会看到代码使用 -1 转换为无符号值以获得类型的最大无符号值,因为它最终总是 -1 + UMAX + 1UMAX

关于c - 无符号类型和更大的有符号类型之间的隐式转换行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23994293/

相关文章:

c++ - 在 C++ 中用零初始化局部数组

c - 洪水填充算法迷宫

c++ - 为什么 bool(val) 比 val.operator bool() 更喜欢双重隐式转换?

c++ - 如何防止std::is_constructible中的隐式转换

c - 是否有任何 C 标准中定义的通用 printf-ish 例程

c - C中的双指针const正确性警告

c - C 中的递归列表循环

c - 是什么导致了 SIGSEGV?

c - 如何在 Windows 上通过 clang 使用 C99 复数?

C数组随机数存储