2

I have an array of 8 bytes and I'm trying to convert it to a signed long in C++, and can't seem to figure it out. From what I could tell long ints are only 4 bytes, can anybody provide some information on this? Is it going to matter if it is 32 or 64 bit?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Bob Bobbio
  • 577
  • 2
  • 5
  • 10
  • Post a bit more on what you want to achieve, possibly with an example. – Shamim Hafiz - MSFT Nov 10 '10 at 07:49
  • 1
    See also: http://stackoverflow.com/questions/271076/what-is-the-difference-between-an-int-and-a-long-in-c and http://stackoverflow.com/questions/589575/c-size-of-int-long-etc – littlegreen Nov 10 '10 at 07:59
  • Though they're typically only available for 16 and 32 bit values, you might find some parallels with the "ntohl" family of functions. For Linux/GCC, they're implemented over bits/byteswap.h which also has __bswap_64, though that's all highly non-Standard it does illustrate use of the Intel's bswap assembly language instruction, and rorw/rorl for older CPUs. On FreeBSD, there's a sys/endian.h header. – Tony Delroy Nov 10 '10 at 08:15

5 Answers5

11

You probably should use a int64_t which is guaranteeed to be 8 bytes long.

You don't state how your data is represented (its endianness) into your array but you might use reinterpret_cast<> or even better: use shift operations to "build" your integer.

Something like:

unsigned char array[8] = { /* Some values here */ };
uint64_t value = 
  static_cast<uint64_t>(array[0]) |
  static_cast<uint64_t>(array[1]) << 8 |
  static_cast<uint64_t>(array[2]) << 16 |
  static_cast<uint64_t>(array[3]) << 24 |
  static_cast<uint64_t>(array[4]) << 32 |
  static_cast<uint64_t>(array[5]) << 40 |
  static_cast<uint64_t>(array[6]) << 48 |
  static_cast<uint64_t>(array[7]) << 56;
ereOn
  • 53,676
  • 39
  • 161
  • 238
  • A `long` is at least 4 bytes long. It can be more. Much, much more. – aib Nov 10 '10 at 08:00
  • @aib: I'm using a `uin64_t` in my example, not a `long`. Why the downvote ? – ereOn Nov 10 '10 at 08:01
  • You did, but you changed your answer. Clever :) – littlegreen Nov 10 '10 at 08:02
  • Can't undo the downvote yet. Unfortunately, stdint.h types are also C99-only. – aib Nov 10 '10 at 08:13
  • ```reinterpret_cast``` would violate strict aliasing rules and cause undefined behavior. – jupp0r Dec 09 '15 at 16:40
  • @jupp0r: Despite what the standard says, I have yet to see a platform where using `reinterpret_cast` would not give the expected result in this case. I get your point, and agree on the theory but practicality often beats purity, and I believe this is such a case. – ereOn Dec 10 '15 at 19:26
  • @ereOn: While I agree with your general statement, average life time of code you write today is 10 years. Optimizers get better quite rapidly with all the innovation we see from LLVM and they could well be starting to rely on strict aliasing in the near future. Bugs introduced by this would be really hard to track down. – jupp0r Dec 11 '15 at 11:33
5

Another way of conversion between data types, which I find convenient in some cases, is to use the union data type, which allows you to access the same memory portion as different data types. Of course all other remarks regarding endianness, size of data-types etc. still hold.

For example:

union bytes {
    unsigned char c[8];
    uint64_t l;
} myb;
myb.c[0] = 0;
myb.c[1] = 1;
myb.c[2] = 0;
myb.c[3] = 0;
myb.c[4] = 0;
myb.c[5] = 0;
myb.c[6] = 0;
myb.c[7] = 0;
cout << "value of myb.l: " << myb.l << "\n";
Itamar Katz
  • 9,544
  • 5
  • 42
  • 74
1

Why not just something like the following?

uint8_t start_arr[8] = {0,1,2,3,4,5,6,7};
uint64_t val = (uint64_t)(*(uint64_t*)&start_arr[0]);
std::cout << std::hex << val << std::endl;
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
John smith
  • 160
  • 6
  • 1
    Don't do this. This type punning is undefined behaviour. It will work if uint64_t has no alignment requirements (ex x86). If you do this disable strict aliasing in your compiler. – Mihai Andrei Dec 26 '19 at 09:36
0

Some long integers are 8 bytes, some are 4. The 8 byte variant usually exists only on 64-bit systems. Check this page if you want to get an idea.

Of course, we don't know what it is in your case, so you'd have to post more details.

To be on the safe side, you could decide to put the 8 bytes into 2 long integers anyway. That way, it will always work. In the worst case you'd be wasting half your storage space.

littlegreen
  • 7,290
  • 9
  • 45
  • 51
0

Only C99 has types guaranteed to hold 64 bits of information - long long and int*64_t. For C++, you should look for a BigInt class/library. Or, as has been suggested, roll your own class using two longs.

aib
  • 45,516
  • 10
  • 73
  • 79
  • how about ```std::int_fast64_t``` which is defined in the standard. There are fast and least versions depending on whether you value space or speed. – rial Mar 09 '21 at 15:41