Is there a way to create a uint64_t variable that can be sent by Serial.print()

Hi,

I need to be able to check out what my code is doing but I can't seem to be able to Serial.print a 64 bit anything to the monitor to check it out. Does anyone know a way to do this?
The type long is almost good enough but it falls short at the higher end of the 64 bit words.
I can do all of it except the variable that are 48bits long and of cause there is no unint48_t.
Is there a way to typedef one of them?
It probably still won't work thought in Serial.print()!!
My only salvation may be to use floats or doubles. According to Bjarne Stroustrup author of the ANSI based document on C++ the way to implement ansi compliant c++ is to have the following size types: of course this was in the 1990's.

type size in bytes type size in bytes
==== ======= ==== =======
char 1 float 4
short 2 double 8
int 2 or 4 long double 12 or 16
long 4 or 8

Is it the band width of the microprocessor the limiting element as to whether it is 4 or 8 bytes for the long?
I have bought an Arduino Due which has a 32 bit buss instead of an 8 bit buss.
Will that be easy to convert my Sketch to that implementation or will I still have the problem?

String CRAddress;


void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
delay(500);
}

void loop() {
  // put your main code here, to run repeatedly:
 CRAddress = "994967275";
 uint64_t iCRAddress = ConvertToInt64(CRAddress);
  Serial.println( iCRAddress);  <===== this is not cooperating.
//11042563100175  000010100000101100001100000011010000111000001111  48

}


uint32_t ConvertToInt32(String CRAddress)
{
  uint32_t answer = 0;
  int Length = CRSddress.length();
  for (int i = 0; i < Length; i++)
  {
    answer += CRSddress.charAt(i) * pow(10,(Length - i));
  }
  return answer;
}

uint64_t ConvertToInt64(String CRAddress)
{
  uint64_t answer = 0;
  int Length = CRSddress.length();
  for (int i = 0; i < Length; i++)
  {
    answer += CRSddress.charAt(i) * pow(10,(Length - i));
  }
  return answer;
}

Thanks,
pamam

Do not user pow for calculating powers of 10. It is a floating point function and not accurate enough for your needs.
Edit: In fact a good rule would be never use pow at all with integers, and almost universally you can just by a little thought and replacing with repeated multiplication.

Also charAt returns the ASCII code, and ‘0’ has the code 48. So you are adding the wrong amounts....

 uint32_t ConvertToInt32(String CRAddress)
{
  uint32_t answer = 0;
  int Length = CRSddress.length();
  for (int i = 0; i < Length; i++)
  {
    answer = answer * 10;
    answer += CRSddress.charAt(i) - 48;
  }
  return answer;
}

uint64_t ConvertToInt64(String CRAddress)
{
  uint64_t answer = 0;
  int Length = CRSddress.length();
  for (int i = 0; i < Length; i++)
  {
    answer = answer * 10;
    answer += CRSddress.charAt(i) - 48;
  }
  return answer;
}

Print as two 32 bit parts in hex. Otherwise you will need a int64 to string routine.

You need to modify Print (or create a related function) rather than search for a different data type.
integer to ascii functions aren't too difficult to write - you can pretty much take the existing code in Print.cpp and add functions copied from the "long" print code with the data types changed to "uint64_t"
(Untested):

size_t print64(uint64_t n)
{
  uint8_t base = 10;
  char buf[3 * sizeof(uint64_t) + 1];   // "big enough" buffer.
  char *str = &buf[sizeof(buf) - 1];
  *str = '\0';
  do {
    char c = n % base;
    n /= base;
    *--str =  c + '0';
  } while(n);

  return write(str);
}

"double" on an AVR is still only 32 bits, so that won't help. (it's 64bits on Due, though.)

What about long on the Due? 32 or 64?

pamam:
Is it the band width of the microprocessor the limiting element as to whether it is 4 or 8 bytes for the long?

You mean bus width, not bandwidth.

Generally it’s a choice of the compiler writer. Bus width is one possible consideration on int/long size, but mainly it’s down to how efficiently the CPU instruction set can handle 16/32/64 bit data sizes and what hardware acceleration, if any, is available for maths operations.

It appears related to bus-width since a generalisation says that a CPU with bus width X usually also has native support for integer arithmetic of at least width X also. But it’s certainly not the main reason, lots of other design considerations are thrown in the mix.

If you want guaranteed sizes use the stdint types everywhere. Then you know what you are getting.

This is how I show 64-bit value on Serial Monitor using print() method.

void setup() 
{
  Serial.begin(9600);
  union
  {
    uint64_t x;// = 0x1234567812345678;
    uint32_t myData[2];
  }data;
  data.x = 0x12345678ABCDEF12;
  Serial.print(data.myData[1], HEX); //shows: 12345678
  Serial.println(data.myData[0], HEX); //shows: ABCDEF12
}

void loop() 
{
 
}

@GolamMostafa, you will need to add leading zeroes. Try it with this data and see what happens

data.x = 0x1234567800CDEF12

sterretje:
@GolamMostafa, you will need to add leading zeroes. Try it with this data and see what happens

data.x = 0x1234567800CDEF12

Thanks for the meticulous observation. There would be a need to add more codes so that the leading zeros are printed.

The bodged-up easy way (for debug purposes) would be...

uint64_t x = 0x1234567800CDEF12;

Serial.print((uint32_t)(x >> 32), HEX);
Serial.print(":");
Serial.println((uint32_t)x, HEX);

Good! Elegant way; but, it still misses leading 0s.

GolamMostafa:
but, it still misses leading 0s.

template<typename IntType>
void printHex(IntType val, Print *ptr = &Serial) {
  ptr->print("0x ");
  for (int8_t shift = 8 * sizeof(val) - 4; shift >= 0; shift -= 4) {
    uint8_t hexDigit = (val >> shift) & 0xF;
    ptr->print(hexDigit, HEX);
    if (((shift & 0xF) == 0) && (shift > 0)) {
      ptr->print(" ");
    }
  }
}

template<typename IntType>
void printlnHex(IntType val, Print *ptr = &Serial) {
  printHex(val, ptr);
  ptr->println();
}

void setup() {
  uint8_t w = 0x6;
  uint16_t x = 0xC4D;
  uint32_t y = 0x20CC23;
  uint64_t z = 0x4CF3BE4;

  Serial.begin(115200);
  delay(1000);

  printlnHex(w);
  printlnHex(x);
  printlnHex(y);
  printlnHex(z);
}

void loop() {
}
0x 06
0x 0C4D
0x 0020 CC23
0x 0000 0000 04CF 3BE4

GolamMostafa:
Good! Elegant way; but, it still misses leading 0s.

At least you can see where the low order 32-bits start, and therefore insert the missing zeros.
As I said, for debugging only. No need to bloat the codebase with more code than necessary just for debug output.

Well I've got my work cut out for me with all these great suggestions and code snippets. It's amazing what one does not think of with no sounding board to bounce ideas off: but this forum is the best sounding board I've ever been on.

cpbbc, westfw, aarg, gfvalvo, GolamMostafa, and Sterretje
Thanks to all of you for your help,

pamam