C 演员和字符符号



所以最近,我读到了一个关于C中三种不同类型的问题,char/unsigned char/signed char。我现在遇到的问题不是我迄今为止遇到的问题(我的程序在所有测试的计算机上都能正常工作,并且只针对小端(基本上所有使用 Windows/Linux 的现代桌面和服务器,对吗?我经常重用我定义的 char 数组,用于保存"字符串"(当然不是真正的字符串)作为临时变量。例如,我只是重用像 array[0] 这样的成员之一,而不是向堆栈添加另一个字符。但是,我基于这样一个事实,即 char 总是会被签名,直到我今天读到它实际上取决于实现。如果我现在有一个字符并为其分配负值,会发生什么情况?

char unknownsignedness = -1;

如果我写

unsigned char A = -1;

我认为 C 样式强制转换将简单地重新解释位,并且 A 表示为无符号类型的值变得不同。我说这些C式演员只是对位的重新诠释是对吗?我现在指的是已签名的<->未签名的转换。

因此,如果实现将 char 设置为未签名,我的程序会停止按预期工作吗?取最后一个变量,如果我现在这样做的话

if (A == -1)

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

以下代码打印No

#include <stdio.h>
int
main()
{
    unsigned char a;
    a = -1;
    if(a == -1)
        printf("Yesn");
    else
        printf("Non");
    return 0;
}

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

`(int)a == -1`
由于a为 255,

因此(int)a仍然是 255,并且检验结果为 false。

unsigned char a = -1;

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

如果新类型是无符号的,则通过重复添加 or 来转换值 比新类型中可以表示的最大值多减 1,直到该值在新类型的范围内

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

if (a == -1)

6.3.1.8/1 中有很长一段话:

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

否则,如果两个操作数都有

有符号整数类型或两个操作数都有无符号整数类型 整数类型,具有较小整数转换秩类型的操作数为 转换为具有更高等级的操作数类型。

否则,如果具有无符号整数类型的操作数的秩大于或 等于另一个操作数类型的秩,然后操作数与 有符号整数类型转换为带无符号的操作数的类型 整数类型。

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

否则,两个操作数都将转换为无符号整数类型 对应于具有有符号整数类型的操作数的类型。

unsigned char的等级低于int

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

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

unsigned char A = -1;

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

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

if (A == -1)

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

是的,你必须小心普通char.

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

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

输出:

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

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

最新更新