【问题标题】:Store signed char inside unsigned int将签名的字符存储在 unsigned int 中
【发布时间】:2016-01-06 20:22:59
【问题描述】:

我有一个 unsigned int,它实际上存储了一个有符号的 int,而有符号的 int 范围从 -128 到 127。

我想将此值存储回 unsigned int 以便我可以简单地 应用掩码 0xFF 并获取签名字符。

如何进行转换?

unsigned int foo = -100;
foo = (char)foo;
char bar = foo & 0xFF;
assert(bar == -100);

【问题讨论】:

  • 我无法理解你的问题。
  • 这会给您带来预期的结果还是意想不到的结果?
  • 请注意:'char'、'signed char' 和 'unsigned char' 是三种不同的类型,其中 'char' 是否有符号,但不同(使用有符号字符并避免位操作)
  • signed char bar = foo; 这样的隐式转换会产生相同的结果。
  • “我有一个无符号整数,实际上存储了一个有符号整数”——为什么?为什么不首先将其存储在有符号的 int 中?

标签: c data-conversion


【解决方案1】:

& 0xFF 操作将产生一个在0255 范围内的值。以这种方式不可能得到负数。因此,即使您在某处使用了& 0xFF,您仍然需要稍后应用转换以达到-128127 的范围。

在您的代码中:

char bar = foo & 0xFF;

存在到char 的隐式转换。这依赖于实现定义的行为,但这将适用于除了最深奥的系统之外的所有系统。最常见的实现定义是将unsigned char 转换为char 时应用的转换的逆。

(您的上一行 foo = (char)foo; 应该被删除)。

然而,

char bar = foo;

会产生完全相同的效果(同样,除了那些深奥的系统)。

【讨论】:

    【解决方案2】:

    由于unsigned int foo 值未达到-128127 的边界,隐式转换将适用于这种情况。但是,如果 unsigned int foo 具有更大的值,那么在将其存储在 char 变量中时,您会丢失字节,并且会在您的程序中得到意想不到的结果。

    【讨论】:

    • C 不保证会出现这种情况。我不确定 C++,但如果你的答案是针对 C++ 的,那么你应该这么说。
    • 据我所知,C 和 C++ 在这方面没有区别。
    【解决方案3】:

    回答 C,

    如果您有一个unsigned int,其值是通过分配char 类型的值(其中char 恰好是有符号类型)或signed char 类型的值来设置的,其中分配的值为负,那么存储的值是分配的负值与UINT_MAX 的算术和。在我遇到的任何 C 系统上,这将远远超出(签名的)char 可表示的值范围。如果将该值转换回(有符号)char,无论是隐式还是通过强制转换,“结果要么是实现定义的,要么是实现定义的信号被引发”(C2011,6.3.1.3/3)。

    以一种避免实现定义的行为的方式转换回原始char 值有点棘手(但依赖实现定义的行为可能会提供更简单的方法)。当然,屏蔽除 8 个最低值位之外的所有位并不能解决问题,因为它总是给你一个正值。此外,它假定char 是 8 位宽,原则上不能保证。它甚至不一定为您提供正确的位模式,因为 C 允许以三种不同方式中的任何一种来表示负整数。

    这是一种适用于任何符合 C 系统的方法:

    unsigned int foo = SOME_SIGNED_CHAR_VALUE;
    signed char bar;
    
    /* ... */
    
    if (foo <= SCHAR_MAX) {
        /* foo's value is representable as a signed char */
        bar = foo;
    } else {
        /* mask off the highest-order value bits to yield a value that fits in an int */
        int foo2 = foo & INT_MAX;
    
        /* reverse the conversion to unsigned int, as if unsigned int had the same
           number of value bits as int; the other bits are already accounted for */
        bar = (foo2 - INT_MAX) - 1;
    }
    

    这仅依赖于 C 本身定义的整数表示和转换的特性。

    【讨论】:

      【解决方案4】:

      不要这样做。

      强制转换为较小的尺寸可能会截断该值。从有符号转换为无符号或相反可能会导致错误的值(例如 255 -> -1)。

      如果您必须使用不同的数据类型进行计算,请选择一种常见的类型,最好是有符号和长整数(32 位),并在向下转换之前检查边界(减小尺寸)。

      Signed 可帮助您检测下溢(例如,当结果小于 0 时)、long int(或简单地说:int,表示自然字长)适合机器(32 位或 64 位),并且足够大用于大多数用途。

      还要尽量避免公式中的混合类型,尤其是当它们包含除法 (/) 时。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多