【问题标题】:C++ copying integer to char[] or unsigned char[] errorC++ 将整数复制到 char[] 或 unsigned char[] 错误
【发布时间】:2013-06-06 18:01:06
【问题描述】:

所以我使用以下代码将整数放入 char[] 或 unsigned char[]

(unsigned???) char test[12];

test[0] = (i >> 24) & 0xFF;
test[1] = (i >> 16) & 0xFF;
test[2] = (i >> 8) & 0xFF;
test[3] = (i >> 0) & 0xFF;

int j = test[3] + (test[2] << 8) + (test[1] << 16) + (test[0] << 24);

printf("Its value is...... %d", j);

当我使用 unsigned char 类型和值 1000000000 时,它会正确打印。

当我使用 char 类型(相同值)时,会打印 98315724?

所以,问题真的是谁能解释到底发生了什么?


在检查两个不同数字的二进制文件后,我仍然无法弄清楚发生了什么。我认为签名是当 MSB 设置为 1 表示负值(但负字符?wth?)

我明确告诉缓冲区要插入什么,以及如何解释内容,所以不明白为什么会发生这种情况。

为了清楚我检查的内容,我在下面包含了二进制/十六进制。

11 1010 1001 1001 1100 1010 0000 0000 // 二进制表示 983157248

11 1011 1001 1010 1100 1010 0000 0000 // 二进制表示 1000000000

3 A 9 9 C A 0 0 // 十六进制表示 983157248

3 B 9 A C A 0 0 // 十六进制表示 1000000000

【问题讨论】:

  • C 并没有真正的“字符”;它只有小整数。 char 只是最小整数类型的名称,最小范围为[-127, 127](如果有符号)或[0, 255](如果无符号),并且(不幸的是)它是否有符号是实现定义的。对于此用例,您必须使用unsigned char
  • 另外,为避免在将某些内容移入int 的符号位时触发未定义的行为,您需要在uint32_t 中进行重组,然后再转换为int

标签: c++ arrays integer char unsigned


【解决方案1】:

除了 Kerrek SB 的回答之外,请考虑以下几点:

计算机(几乎总是)使用 twos-complement notation 表示负数,高位用作“负”指示符。考虑到计算机将专门处理有符号位,问问自己当你对有符号类型执行移位时会发生什么。

您可能想在 StackOverflow 上阅读 Why does left shift operation invoke Undefined Behaviour when the left side operand has negative value? 以获得提示。

【讨论】:

  • 有趣的是,我可以像以前一样插入值并在最后一分钟插入一个(丑陋的)演员,即 unsigned char* tmp = (unsigned char*)test;然后在打印中使用 tmp。不过谢谢,这真的很有帮助=)
  • 正确 - 因为转换告诉编译器如何解释该值。计算机存储signed 值与unsigned 的值没有任何不同(尽管原则上可以)。唯一的区别是计算机处理数据的方式。例如,有不同的指令来执行有符号和无符号乘法。无论是哪个版本,数据都存储在相同的寄存器中或只是通用内存中。不在“特殊”signedunsigned 寄存器或内存中。
【解决方案2】:

当您说i &amp; 0xFF 等时,您正在创建[0, 256) 范围内的值。但是(您的)char 的范围为[-128, +128),因此您实际上无法明智地存储这些值(即行为是由实现定义的,而且推理起来很乏味)。

unsigned char 用于无符号值。线索就在名字里。

【讨论】:

  • 我认为名称部分在这里不适用,因为即使您使用 unsigned chars,unsigned int 仍然不适合(除非您仍然使用 &0xff,但是您不能拥有所有您的 int 可以表示的值)。
  • 这不是 OP 面临的问题,尽管一开始将 unsigned 的东西推入 signed 盒子并不是一个好主意。问题是有符号类型的左移。
  • 我以为 0xFF 只是去掉了整数的最后 8 位。我认为这不太对,因为 memcpy(&test,&i, 4);不做转变,但仍然有同样的问题
  • 尼克,你的回答听起来很明智!当您转换有符号类型时,您是否使用与 MSB 相同的值?我知道将 16 位有符号值扩展到 32 位,您只需复制 MSB。另外,由于我所有的值都是正数,所以我猜我可以使用 unsigned int。
  • 等等,unsigned int 没有意义,需要正确输入数组>.>
【解决方案3】:

这一切都与internal representation 以及每个type 使用data 来解释它的方式有关。在signed characterinternal representation 中,字节的第一位保存符号,其他位保存值。当第一位为 1 时,数字为负数,后面的位则代表正值的complement。例如:

unsigned char c;  // whose internal representation we will set at 1100 1011
c = (1 * 2^8) + (1 * 2^7) + (1 * 2^4) + (1 * 2^2) + (1 * 2^1);
cout << c;        // will give 203

                  // inversely:

char d = c;       // not unsigned
cout << d;        // will print -53
                  // as if the first is 1, d is negative, 
                  // and other bits complement of value its positive value
                  // 1100 1011  -> -(complement of 100 1011)
                  // the complement is an XOR +1   011 0101

                  // furthermore:

char e;           // whose internal representation we will set at 011 0101
e = (1 * 2^6) + (1 * 2^5) + (1 * 3^2) + (1 * 2^1);
cout << e;        // will print 53

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多