【问题标题】:C cast and char signednessC cast 和 char 签名
【发布时间】:2015-01-01 18:11:13
【问题描述】:

最近,我读到了一个关于 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)

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

【问题讨论】:

  • 什么选角?任何地方都没有铸造。如果您想存储二进制(非字符)数据,请使用更好的 (IMO) int8_tuint8_t 标准类型。
  • 我的实现不支持 C99,我认为 int8_t 是针对那个版本的
  • 如果我将一个有符号值分配给一个无符号值,会不会进行强制转换?还是只有在数据大小不匹配时才会进行强制转换?
  • 有自动转换,而不是强制转换。铸造是当你写像(unsigned char) -1
  • 如果确实像上面的例子一样,我为无符号数据类型分配了一个负值,会发生什么?这些位是否被重新解释?还是这些位本身发生了变化?还有比较中会发生什么(我在问题中的最后一个例子)。

标签: c char signedness


【解决方案1】:

以下代码打印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 == -1unsigned charint 进行比较,因此适用通常的提升规则;因此,它被解释为

`(int)a == -1`

由于a 为255,(int)a 仍为255,测试结果为假。

【讨论】:

  • "实现定义的值" 在所有符合标准的实现中都将是 UCHAR_MAX
  • 我想我明白了:我可以回到我的代码并更改所有 char somevariable = 负值和类似的比较,因为如果 char 被实现为无符号,程序将停止正常工作在某些情况下。我说的对吗?
【解决方案2】:
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

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

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

【讨论】:

    【解决方案3】:
    unsigned char A = -1;
    

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

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

    if (A == -1)
    

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

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

    【讨论】:

    • “结果为 255”。那就是如果您的 char 是 8 位。不保证。 “8位机,sizeof(int) == sizeof(char)”。 int 至少为 16 位。
    • 同意。我假设 char 是 8 位。有没有人见过不同的东西?已编辑。
    • “有没有人见过不同的东西?”可能重复:stackoverflow.com/questions/2098149/…
    【解决方案4】:

    我认为这个问题最好通过一个简单的例子来回答(警告: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 中是安全的。

    【讨论】:

    • 这是一道 C 题。 C 和 C++ 是不同的语言。
    • @jch:阅读第一行的说法,看看在这个例子中使用 C++ 的解释。
    • 所以如果我从问题“A == -1”中举个例子,我必须明确地转换为“(signed char)A == -1”才能让它工作?
    • @user209347 正确。 unsigned 的值 -1255
    猜你喜欢
    • 2011-01-24
    • 2011-06-11
    • 1970-01-01
    • 2019-01-13
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多