user1161604
user1161604

Reputation: 353

How do I convert a 64bit integer to a char array and back?

I am having trouble converting a int64_t to a char array and back. I don't know what is wrong with the code below, it makes complete logical sense to me. The code works for a as shown, but not the second number b which clearly falls into the range of int64_t.

#include <stdio.h>
#include <stdint.h>

void int64ToChar(char mesg[], int64_t num) {
  for(int i = 0; i < 8; i++) mesg[i] = num >> (8-1-i)*8;
}

int64_t charTo64bitNum(char a[]) {
  int64_t n = 0;
  n = ((a[0] << 56) & 0xFF00000000000000U)
    | ((a[1] << 48) & 0x00FF000000000000U)
    | ((a[2] << 40) & 0x0000FF0000000000U)
    | ((a[3] << 32) & 0x000000FF00000000U)
    | ((a[4] << 24) & 0x00000000FF000000U)
    | ((a[5] << 16) & 0x0000000000FF0000U)
    | ((a[6] <<  8) & 0x000000000000FF00U)
    | ( a[7]        & 0x00000000000000FFU);
  return n;
}

int main(int argc, char *argv[]) {
  int64_t a = 123456789;
  char *aStr = new char[8];
  int64ToChar(aStr, a);
  int64_t aNum = charTo64bitNum(aStr);
  printf("aNum = %lld\n",aNum);

  int64_t b = 51544720029426255;
  char *bStr = new char[8];
  int64ToChar(bStr, b);
  int64_t bNum = charTo64bitNum(bStr);
  printf("bNum = %lld\n",bNum);
  return 0;
}

output is

aNum = 123456789
bNum = 71777215744221775

The code also gives two warnings that I don't know how to get rid of.

warning: integer constant is too large for ‘unsigned long’ type
warning: left shift count >= width of type

Upvotes: 12

Views: 22740

Answers (4)

gdj
gdj

Reputation: 71

void int64ToChar(char mesg[], int64_t num) {
    *(int64_t *)mesg = num; //or *(int64_t *)mesg = htonl(num);

}

Upvotes: 1

Jack
Jack

Reputation: 133577

This is rather simple, the problem is that you are shifting bits in the char array but size of a[i] is 4 byes (upcast to int), so your shift just goes over range. Try replacing this in your code:

int64_t charTo64bitNum(char a[]) {
  int64_t n = 0;
  n = (((int64_t)a[0] << 56) & 0xFF00000000000000U)
    | (((int64_t)a[1] << 48) & 0x00FF000000000000U)
    | (((int64_t)a[2] << 40) & 0x0000FF0000000000U)
    | (((int64_t)a[3] << 32) & 0x000000FF00000000U)
    | ((a[4] << 24) & 0x00000000FF000000U)
    | ((a[5] << 16) & 0x0000000000FF0000U)
    | ((a[6] <<  8) & 0x000000000000FF00U)
    | (a[7]        & 0x00000000000000FFU);
  return n;
}

In this way you'll cast the char to a 64bit number before doing the shift and you won't go over range. You'll obtain correct results:

entity:Dev jack$ ./a.out 
aNum = 123456789
bNum = 51544720029426255

Just a side note, I think this would work fine too, assuming you don't need to peek inside the char array:

#include <string.h>

void int64ToChar(char a[], int64_t n) {
  memcpy(a, &n, 8);
}

int64_t charTo64bitNum(char a[]) {
  int64_t n = 0;
  memcpy(&n, a, 8);
  return n;
}

Upvotes: 11

Andrew Cooper
Andrew Cooper

Reputation: 32576

In charTo64bitNum you need to cast the char to 64-bit before you shift it:

(((int64_t)a[0] << 56) & 0xFF00000000000000U)

Upvotes: 0

Tim
Tim

Reputation: 35933

Are you on a 32bit machine? IIRC I think that the U suffix only means either 'unsigned int' or 'unsigned long', both of which are 32bits on a 32bit machine. I think you want a 'unsigned long long' (64bit) literal in your bit shifts, or 0xFF00000000000000ULL

http://en.kioskea.net/faq/978-c-language-handling-64-bit-integers#unsigned-64-bit-integer

Upvotes: 0

Related Questions