0

所以最近,我读到了一个关于 C 中三种不同类型 char/unsigned char/signed char 的问题。我现在遇到的问题不是我到目前为止遇到的问题(我的程序在所有经过测试的计算机上都能正常工作,并且只针对 little-endian(基本上所有使用 Windows/Linux 的现代台式机和服务器对吗?)。我经常重用一个 char我为保存一个“字符串”(当然不是真正的字符串)作为临时变量而定义的数组。例如,我没有将另一个字符添加到堆栈中,而是重用了数组 [0] 之类的成员之一。但是,我基于此策略事实上, char 总是会被签名, 直到我今天读到它实际上取决于实现. 如果我现在有一个 char 并且我给它分配一个负值会发生什么?

char unknownsignedness = -1;

如果我写

unsigned char A = -1;

我认为 C 风格的转换只会重新解释位,并且 A 表示为无符号类型的值会变得不同。我对这些 C 风格的演员表只是对位的重新解释是对的吗?我现在指的是有符号 <-> 无符号转换。

因此,如果实现的 char 为无符号,我的程序会按预期停止工作吗?取最后一个变量,如果我现在这样做

if (A == -1)

我现在将一个无符号字符与一个有符号字符值进行比较,所以这会简单地比较不关心符号的位还是会返回 false,因为显然 A 不能为 -1?我很困惑在这种情况下会发生什么。这也是我最关心的问题,因为我经常使用这样的字符。

4

4 回答 4

4

以下代码打印No

#include <stdio.h>

int
main()
{
    unsigned char a;

    a = -1;

    if(a == -1)
        printf("Yes\n");
    else
        printf("No\n");

    return 0;
}

代码a = -1将实现定义的值分配给a; 在大多数机器上, a 将为 255。测试将 a与aa == -1进行比较,因此适用通常的提升规则;因此,它被解释为unsigned charint

`(int)a == -1`

因为a是 255,(int)a仍然是 255,测试结果为假。

于 2015-01-01T18:29:21.707 回答
4
unsigned char a = -1;

ISO/IEC 9899:1999 在 6.3.1.3/2 中说:

如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内

我们加(UCHAR_MAX+1)一次-1,结果是UCHAR_MAX,显然在 的范围内unsigned char

如果 (a == -1)

6.3.1.8/1 中有一段很长的内容:

如果两个操作数具有相同的类型,则不需要进一步转换。

否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则具有较小整数转换等级的类型的操作数将转换为具有较高等级的操作数的类型。

否则,如果无符号整数类型的操作数的等级大于或等于另一个操作数类型的等级,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。

否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为有符号整数类型的操作数的类型。

否则,两个操作数都转换为与带符号整数类型的操作数类型对应的无符号整数类型。

的等级unsigned char小于的等级int

如果intcan 表示所有可以的值unsigned char(通常是这种情况),则两个操作数都转换为int,并且比较返回false

如果int不能表示 中的所有值unsigned char,这可能发生在带有 的稀有机器上sizeof(int)==sizeof(char),那么两者都被转换为unsigned int-1被转换为UINT_MAX恰好与 相同的UCHAR_MAX值,然后比较返回true

于 2015-01-01T18:59:19.283 回答
3
unsigned char A = -1;

结果为 255。分配或初始化时没有重新解释。A-1只是1二进制补码符号中的一堆位,其中 8 个是逐字复制的。

比较有点不同,因为字面-1量是int类型。

if (A == -1)

将在比较之前进行提升(隐式转换)(int)A,因此您最终会将 255 与 -1 进行比较。不相等。

是的,你必须小心 plain char

于 2015-01-01T18:31:28.773 回答
-1

我认为这个问题最好通过一个简单的例子来回答(警告:C++,但请参阅我的推理解释):

char c = -1;
unsigned char u = -1;
signed char s = -1;
if (c == u)
        printf("c == u\n");
if (s == u)
        printf("s == u\n");
if (s == c)
        printf("s == c\n");
if (static_cast<unsigned char>(s) == u)
        printf("(unsigned char)s == u\n");
if (c == static_cast<char>(u))
        printf("c == (char)u\n");

输出:

s == c
(unsigned char)s == u
c == (char)u

C按原样使用时对值的处理方式不同,但您是正确的,因为转换只会重新解释这些位。我在这里使用了 C++static_cast来表明编译器可以进行这种转换。在 C 语言中,您只需在括号中添加类型前缀即可。没有编译器检查来确保强制转换在 C 中是安全的。

于 2015-01-01T18:22:22.990 回答