使用按位包含OR的错误结果

问题描述 投票:3回答:3

我无法弄清楚为什么包容性OR会返回错误的结果。

char arr[] = { 0x0a, 0xc0 };
uint16_t n{};

n = arr[0]; // I get 0x000a here.
n = n << 8; // Shift to the left and get 0x0a00 here.
n = n | arr[1]; // But now the n value is 0xffc0 instead of 0x0ac0.

这个例子中的错误是什么?控制台应用程序,MVS社区2017。

c++ bit-manipulation bitwise-operators
3个回答
6
投票

无意识的0xff是由sign bit extension0xc0引起的。

0xc0 = 0b11000000

因此,最高位被设置,这意味着为char(作为signed char)的符号。

请注意,C ++中的所有算术运算和按位运算至少使用int(或unsigned int)。较小的类型在之前被提升并且之后被剪辑。

请注意,char可能已签名或未签名。这是依赖于编译器的实现。显然,它是在OP的情况下签署的。为防止意外的符号扩展,参数必须变为无符号(足够早)。

示范:

#include <iostream>

int main()
{
  char arr[] = { '\x0a', '\xc0' };
  uint16_t n{};

  n = arr[0]; // I get 0x000a here.
  n = n << 8; // Shift to the left and get 0x0a00 here.
  n = n | arr[1]; // But now the n value is 0xffc0 instead of 0x0ac0.
  std::cout << std::hex << "n (wrong): " << n << std::endl;
  n = arr[0]; // I get 0x000a here.
  n = n << 8; // Shift to the left and get 0x0a00 here.
  n = n | (unsigned char)arr[1]; // (unsigned char) prevents sign extension
  std::cout << std::hex << "n (right): " << n << std::endl;
  return 0;

}

会议:

g++ -std=c++11 -O2 -Wall -pthread main.cpp && ./a.out
n (wrong): ffc0
n (right): ac0

关于coliru的生活演示

注意:

我不得不改变 char arr[] = { 0x0a, 0xc0 };char arr[] = { '\x0a', '\xc0' }; 来到严重的编译器投诉。我猜,这些投诉与这个问题密切相关。


0
投票

通过这样做我让它正常工作:

int arr[] = { 0x0a, 0xc0 };
int n{};

n = arr[0]; // I get 0x000a here.
n = n << 8; // Shift to the left and get 0x0a00 here.
n = n | arr[1];
std::cout << n << std::endl;

如果将'arr'数组保留为char,则会发生一些截断。


0
投票

您已成为签名整数促销的受害者。

0xc0分配给数组中的第二个元素(因为MVS而签名的char默认值)时,这表示如下:

arr[1] = 1100 - 0000, or in decimal -64

当它被强制转换为uint16_t时,它将被提升为值为-64的整数。这是:

n = 1111 - 1111 - 1100 - 0000 = -64  

由于2's complement实现了整数。

因此:

n          = 1111 - 1111 - 1100 - 0000 
arr[1]     = 0000 - 0000 - 1010 - 0000 (after being promoted)

n | arr[1] = 1111 - 1111 -1110-0000 = 0xffc0
© www.soinside.com 2019 - 2024. All rights reserved.