Data Values Not Represented Correctly?

Hi all --

New to Arduino platform. I have an Arduino Uno. I am a retired software and database developer, so I know that every platform and every language has its quirks. I'm wondering if that's what I'm observing. So I just did this simple program to see what actually happened with variables of different sizes as I was observing results that didn't make sense. Here's the program, followed by the results. Can anyone explain to me what's going on (or not going on)? The last one, the pulseIn() vs pulseInLong() both seem to return a long, so why have both?

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

void loop() {
  uint64_t u64;
  uint32_t u32;
  uint16_t u16;
  uint8_t u8;

  u64 = (uint64_t)0xFAFAFAFAFAFAFAFALL;
  u32 = (uint32_t)0xEBEBEBEBL;
  u16 = (uint16_t)0xA7A7;
  u8 = (uint8_t)0xD;

  char buffer[100];

  sprintf(buffer, "u64:  %016X  U64 size:  %u", u64, (uint16_t)sizeof(u64));
  Serial.println(buffer);
  sprintf(buffer, "u32:  %08X  U32 size:  %u", u32, (uint16_t)sizeof(u32));
  Serial.println(buffer);
  sprintf(buffer, "u16:  %04X  U16 size:  %u", u16, (uint16_t)sizeof(u16));
  Serial.println(buffer);
  sprintf(buffer, "u8:  %02X  U8 size:  %u", u8, (uint16_t)sizeof(u8));
  Serial.println(buffer);
  int pulseReturn;
  pulseReturn = sizeof( pulseIn(2, HIGH, 1000));
  sprintf(buffer, "Size of pulseIn():  %u", pulseReturn);
  Serial.println(buffer);
  pulseReturn = sizeof( pulseInLong(2, HIGH, 1000));
  sprintf(buffer, "Size of pulseInLong():  %u", pulseReturn);
  Serial.println(buffer);

  Serial.flush();

  exit(0);

}

Results:

u64: 000000000000FAFA U64 size: 64250
u32: 0000EBEB U32 size: 60395
u16: A7A7 U16 size: 2
u8: 0D U8 size: 1
Size of pulseIn(): 4
Size of pulseInLong(): 4

pulseInLong() is an alternative to pulseIn() which is better at handling long pulse and interrupt affected scenarios.

Welcome

Try %016LLX and %08LX

Edit: I've tried in Wokwi simulator and it didn't work. A working "solution" is to split the varible in multiple 16bits values, for example
sprintf(buffer, "u32: %04X%04X U32 size: %u", (uint16_t)(u32 >> 16), (uint16_t)(u32 & 0xFFFF), (uint16_t)sizeof(u32));

It also work if you print the number in decimal
sprintf(buffer, "u32: %lu U32 size: %u", u32, (uint16_t)sizeof(u32));

For the u32 you're missing an l in the sprintf

  sprintf(buffer, "u32:  %08lX  U32 size:  %u", u32, (uint16_t)sizeof(u32));
                            ^

Support for 64bit is limited; in this thread from 2011, 64bit was printed using division and modulo.

Note: you don't need the cast for sizeof

You can do the same thing for hexadecimal

  sprintf(buffer, "u64:  %08lX%08lX  U64 size:  %u", (uint32_t)(u64 >> 32), (uint32_t)(u64 & 0xFFFFFFFF), sizeof(u64));

The casts are used to suppress the compiler warning that you should use ll.

OK, so if I modify the code to remove the casts (originally used, redundantly, but to remove any ambiguity of my intent), and to add "LL" and "L" into the format specifiers in sprintf as shown here, I get no results at all from these statements. I could find no indication in language reference that adding the LL indicator into the format specifier is valid syntax, and I'd say the result bears that out:

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

void loop() {
  uint64_t u64;
  uint32_t u32;
  uint16_t u16;
  uint8_t u8;

  u64 = 0xFAFAFAFAFAFAFAFALL;
  u32 = 0xEBEBEBEBL;
  u16 = 0xA7A7;
  u8 = 0xD;

  char buffer[100];

  sprintf(buffer, "u64:  %016LLX  U64 size:  %u", u64, sizeof(u64));
  Serial.println(buffer);
  sprintf(buffer, "u32:  %08LX  U32 size:  %u", u32, sizeof(u32));
  Serial.println(buffer);
  sprintf(buffer, "u16:  %04X  U16 size:  %u", u16, sizeof(u16));
  Serial.println(buffer);
  sprintf(buffer, "u8:  %02X  U8 size:  %u", u8, sizeof(u8));
  Serial.println(buffer);

  Serial.flush();

  exit(0);

}

u64:
u32:
u16: A7A7 U16 size: 2
u8: 0D U8 size: 1

Removing the LL gives the format result I expect, just not the numerical result, as shown here (although the size result on the u64 and u32 statements are a bit curious:

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

void loop() {
  uint64_t u64;
  uint32_t u32;
  uint16_t u16;
  uint8_t u8;

  u64 = 0xFAFAFAFAFAFAFAFALL;
  u32 = 0xEBEBEBEBL;
  u16 = 0xA7A7;
  u8 = 0xD;

  char buffer[100];

  sprintf(buffer, "u64:  %016X  U64 size:  %u", u64, sizeof(u64));
  Serial.println(buffer);
  sprintf(buffer, "u32:  %08X  U32 size:  %u", u32, sizeof(u32));
  Serial.println(buffer);
  sprintf(buffer, "u16:  %04X  U16 size:  %u", u16, sizeof(u16));
  Serial.println(buffer);
  sprintf(buffer, "u8:  %02X  U8 size:  %u", u8, sizeof(u8));
  Serial.println(buffer);

  Serial.flush();

  exit(0);

}

u64: 000000000000FAFA U64 size: 64250
u32: 0000EBEB U32 size: 60395
u16: A7A7 U16 size: 2
u8: 0D U8 size: 1

So if the Uno can't process uint64_t values and I have to use work-arounds, that's OK, but it would be nicer to get at least a compiler warning about that. On the other hand, if I'm doing something totally bone-headed I can handle that -- wouldn't be the first time. I guess that's what I'm trying to determine: Am I, or am I running into platform/language/compiler quirkiness?

As said, 64bit support is limited.

Post #5 gives the solution.

The "long" prefix is a lower-case "l", not upper-case "L"; You luck out on "X", because a "X" causes the number to be printed with ABCDEF instead of abcdef.

avr printf() does not support 64bit integers. See the full documentation here:
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

it would be nicer to get at least a compiler warning about that.

the format string is a string argument to a library function, not a language feature - how deeply do you want the compiler to analyze such things?
In fact, recent C compilers DO analyze format strings, but they usually aren't aware of less-standard libraries (like avr-gcc.) If I enable "all" warnings in the Arduino IDE preferences, I see:

/var/folders/gv/zn3wcml52jq0vvjnd95j8g6h0000gp/T/arduino_modified_sketch_447945/sketch_oct27a.ino: In function 'void loop()':
/var/folders/gv/zn3wcml52jq0vvjnd95j8g6h0000gp/T/arduino_modified_sketch_447945/sketch_oct27a.ino:19:67: warning: unknown conversion type character 'L' in format [-Wformat=]
   sprintf(buffer, "u64:  %016LLX  U64 size:  %u", u64, sizeof(u64));
                                                                   ^
/var/folders/gv/zn3wcml52jq0vvjnd95j8g6h0000gp/T/arduino_modified_sketch_447945/sketch_oct27a.ino:19:67: warning: format '%u' expects argument of type 'unsigned int', but argument 3 has type 'uint64_t {aka long long unsigned int}' [-Wformat=]
/var/folders/gv/zn3wcml52jq0vvjnd95j8g6h0000gp/T/arduino_modified_sketch_447945/sketch_oct27a.ino:19:67: warning: too many arguments for format [-Wformat-extra-args]
/var/folders/gv/zn3wcml52jq0vvjnd95j8g6h0000gp/T/arduino_modified_sketch_447945/sketch_oct27a.ino:21:65: warning: format '%LX' expects argument of type 'long long unsigned int', but argument 3 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
   sprintf(buffer, "u32:  %08LX  U32 size:  %u", u32, sizeof(u32));
                                                                 ^

Thanks for the links to the more comprehensive documentation. That is most helpful, on many fronts.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.