bitshifting unsigned char 和 unsigned long long 出错了

bitshifting unsigned char and unsigned long long gone wrong

这是我(想要)用来解码 unsigned char[] 缓冲区中的数字以进行网络连接的函数。

inline unsigned long long getULongLongLongInt(const unsigned char* buffer)
{
    unsigned long long number= (buffer[0] << 56);
    number|= (buffer[1] << 48);
    number|= (buffer[2] << 40);
    number|= (buffer[3] << 32);
    number|= (buffer[4] << 24);
    number|= (buffer[5] << 16);
    number|= (buffer[6] << 8);
    number|= buffer[7];
    return number;
}

我收到警告 C4293“<<”:移位计数为负数或太大,未定义的行为”四次,用于最高位移位; 这是一个我可以放心忽略的警告,因为编译器无法识别我使用的是无符号 64 位 int 吗?我想不是。但是我该如何解决这个问题?

在表达式中使用时,unsigned char 值被提升为 int。显然,尝试将 int 移动 56 位的效率不是很高。

你必须更明确:

 unsigned long long number= ((unsigned long long)buffer[0] << 56);
    number|= ((unsigned long long)buffer[1] << 48);

...等等。在进行移位操作之前,您必须强制转换为 unsigned long long

不,你不能忽视它。操作数 buffer[i] 的类型为 unsigned char,它可能被提升为 int(如果不是 int,则 unsigned int)。如果56大于等于int的位宽,则移位为UB

你需要写 static_cast<unsigned long long>(buffer[0]) << 56 等等,所以操作数至少要有 64 位长 before 移位。

我认为最好明确说明意图并让编译器的优化器发挥其魔力:

#include <cstdint>
#include <utility>

template<class Unsigned,
std::enable_if_t<std::is_unsigned<Unsigned>::value>* = nullptr
  >
inline Unsigned decode_int_msb(const unsigned char* buffer)
{
  //
  // some helpful types and constants
  //

  using type = Unsigned;
  static constexpr auto bytes = sizeof(type);
  static constexpr auto bits = bytes * 8;

  //
  // a helpful local function
  //

  auto byte = [buffer](auto i) {
    return type(buffer[i]) << bits - ((i+1) * 8);
  };

  //
  // simplified algorithm here
  //

  type acc = 0;
  for(std::size_t i = 0 ; i < bytes ; ++i)
    acc += byte(i);
    return acc;
}

int main(int argc, char** argv)
{

  // force expansion of some templates

  auto x =  decode_int_msb<unsigned long long>(reinterpret_cast<const unsigned char*>(argv[0]));
  auto y =  decode_int_msb<unsigned long>(reinterpret_cast<const unsigned char*>(argv[0]));
  auto z =  decode_int_msb<unsigned short>(reinterpret_cast<const unsigned char*>(argv[0]));
  return x + y + z;
}

unsigned long long 版本的示例汇编程序输出(未内联时):

unsigned long decode_int_msb<unsigned long, (void*)0>(unsigned char const*):
        movzx   ecx, BYTE PTR [rdi+1]
        movzx   edx, BYTE PTR [rdi+2]
        movzx   eax, BYTE PTR [rdi+3]
        mov     rsi, rcx
        sal     rdx, 40
        sal     rsi, 48
        sal     rax, 32
        lea     rcx, [rsi+rdx]
        lea     rdx, [rcx+rax]
        movzx   eax, BYTE PTR [rdi]
        sal     rax, 56
        add     rax, rdx
        movzx   edx, BYTE PTR [rdi+4]
        sal     rdx, 24
        add     rdx, rax
        movzx   eax, BYTE PTR [rdi+5]
        sal     rax, 16
        add     rdx, rax
        movzx   eax, BYTE PTR [rdi+6]
        sal     rax, 8
        add     rax, rdx
        movzx   edx, BYTE PTR [rdi+7]
        add     rax, rdx
        ret

像这样更改代码:

//unsigned long long number= (buffer[0] << 56);
unsigned long long number= ((buffer[0] << 31) << 25);