문제

I have the following function:

void func(unsigned long v)
{
  char max_byte = 0xFF;
  char buffer[8];

  buffer[0] = static_cast<char>((v)       & max_byte);
  buffer[1] = static_cast<char>((v >> 8)  & max_byte);
  buffer[2] = static_cast<char>((v >> 16) & max_byte);
  buffer[3] = static_cast<char>((v >> 24) & max_byte);
  buffer[4] = static_cast<char>((v >> 32) & max_byte);
  buffer[5] = static_cast<char>((v >> 40) & max_byte);
  buffer[6] = static_cast<char>((v >> 48) & max_byte);
  buffer[7] = static_cast<char>((v >> 56) & max_byte);
}

which takes an unsigned long argument and insert its 8 bytes to char buffer ( don't try to figure out why. it is a concise version of a meaningful function).

This code compiles well on 64 bit but on 32 bit I get the following warning:

warning: right shift count >= width of type

referring to lines:

  buffer[4] = static_cast<char>((v >> 32) & max_byte);
  buffer[5] = static_cast<char>((v >> 40) & max_byte);
  buffer[6] = static_cast<char>((v >> 48) & max_byte);
  buffer[7] = static_cast<char>((v >> 56) & max_byte);

I think I understand the warning but I'm not sure what should I do to be able to compile it smoothly on 32 bit as well.

도움이 되었습니까?

해결책 2

unsigned long is only guaranteed to have 32 bits. See here. You need to use unsigned long long to have 64 bits guaranteed.

Even better would be to use a fixed width integer, i.e. uint64_t. They are defined in header <cstdint> (or <stdint.h>).

다른 팁

Use the fixed-width integer types. In this case, you want std::uint64_t.

When writing code that depends on integer size, you really, really need to be using <stdint.h>.

#include <stdint.h>

void func(uint64_t v)
{
  static const uint8_t max_byte = 0xFF; // Let the compiler hardcode this constant.
  uint8_t buffer[8];

  buffer[0] = static_cast<uint8_t>((v)       & max_byte);
  buffer[1] = static_cast<uint8_t>((v >> 8)  & max_byte);
  buffer[2] = static_cast<uint8_t>((v >> 16) & max_byte);
  buffer[3] = static_cast<uint8_t>((v >> 24) & max_byte);
  buffer[4] = static_cast<uint8_t>((v >> 32) & max_byte);
  buffer[5] = static_cast<uint8_t>((v >> 40) & max_byte);
  buffer[6] = static_cast<uint8_t>((v >> 48) & max_byte);
  buffer[7] = static_cast<uint8_t>((v >> 56) & max_byte);
}

I may be wrong with the assumption that none of the answers truly gets to the point of this question, therefore here goes.

Compiling as a 64bit binary a long is defined as a 64bit value (or 8 bytes), whereas a 32 bit binary a long is the same as an int which is 32 bits or 4 bytes.

There are several solutions to the problem:
1. redefine the parameter to a long long or an int64 as suggested in other responses.
2. add a preprocessor define to block out the offending bit operations. Such as...

#ifdef __LP64__
buffer[4] = static_cast<uint8_t>((v >> 32) & max_byte);
buffer[5] = static_cast<uint8_t>((v >> 40) & max_byte);
buffer[6] = static_cast<uint8_t>((v >> 48) & max_byte);
buffer[7] = static_cast<uint8_t>((v >> 56) & max_byte);
#endif


This will ensure that a long is processed according to the processors architecture and not forcing a long to always be 64 bits.
3. Using a union would accomplish the same end result too, for the code provided

void func(unsigned long v)
{
    union {
        unsigned long long  ival;
        unsigned char       cval[8];
    } a;

    a.ival = v;
}

of course if you use c++ then you can store any basic datatype in a similar fashion by modifying the above as follows:

template<class I>
void func(I v) {
    union {
        unsigned long long  ival;
        unsigned char       cval[8];
        I                   val;
    } a;

    a.val = v;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top