Snprintf() not handling %lli or %llu for int64_t and uint64_t respectively

I am trying to handle a 7 byte Desfire card UID.
Things have been fine using a uint32_t variable to hold and display the 4 byte MiFare card UID.

I thought I would use uint64_t instead of uint32_t - unfortunately snprintf() does not appear to handle C format conversion specifier %llu - output is “lu” and a string terminator.

Any ideas what I am missing? Thanks

I guess this statement from 2016 is still valid

@ScruffR Thanks for the quick response - I picked this out from mdma - My guess is that the sprintf is not handling the 64-bit datatype. %lld

To print, I see you have 2 options:

  1. write your own routine to print the long long value
  2. convert to double and print using sprintf

Not sure how to do 1. would you know where to start?
2. I understand. I wonder if there is a library that can be included to support this - also printf() doesn’t work either.

My take would be to go HEX - with that you can take each individual byte as is whether you have 1, 2, 4 or 8 doesn’t matter :wink:

It’s a documented limitation.

As a workaround you can use the Print64 firmware library in the community libraries. The source and instructions can be found in Github.


@rickkas7 @ScruffR Thanks both - and for writing a function to manage this.

@armor, why do you need to convert to decimal at all?

@UMD Good question - the answer is space. I am using backup (retained) RAM (with battery backup) so I am limited to 3K on the Photon. The reason for using backup RAM is that I can search using simple search. Inefficient but still quick enough for my needs, space then becomes the constraint.
The tag reader outputs a card serial number or UID of either 4 bytes or 7 bytes length.

The first, 4 bytes can be stored in a uint32_t with a value of 0-4294967295 that’s 10 chars and if stored as a c-string with null terminator 11 chars - so 7 bytes per entry bigger. When formatting to receive via a command I can use strtoul() and c format printf using %lu.

The second, 7 bytes can be stored in uint64_t with a value of 0-72057594037927935 that’s 17 chars and 18 chars with null terminator or 10 bytes more. I appreciate that BCD could be used but then there is the further translation and it still takes more room. As discussed earlier in the topic the printf format is a problem for uint64_t - now solved and strtoull() works.

@armor, given that the natural data format for 99.999% of computers in the world is binary, the most efficient space utilisation will be to not convert from binary to decimal.

You said:

7 bytes can be stored in uint64_t

uint64_t takes 8 bytes, so the effort of converting to decimal means that you are using one byte more.

uint32_t for the 4 byte UID conversion takes the same amount of space.

To display the UID, you could use something like the following to fill the string buffer with ASCII hexadecimal representation of the UID for the human (other methods can be envisaged of course):

sprintf(buf, "%02X%02X%02X%02X%02X%02X%02X", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]); 

So, an 7 byte NFC tag UID of 0x044A7232214B80 would be displayed as 14 ASCII digits: “044A7232214B80”.

Re efficient searching, a simple iteration through the data will be really quick, so no need to worry about that as an issue.

Schemes can be envisage to handle the data structure of 4 byte vs 7 byte UID’s.

In short,

  • store the UID’s in their raw binary form
  • search by iterating the structure through memory
  • convert to the binary to ASCII hexadecimal for the human

Hope this helps.

1 Like

I don’t disagree with anything you are saying except that normal people do not use hexadecimal!
The other aspect is that using uint64_t and uint32_t means I don’t have to create a special data type and I can very easily implement 7 byte UID support once 4 byte UID support is implemented - yes I would save 1 byte but there again most storage schemes round to the nearest word (4 bytes).