"%ul"
means "%u"
(unsigned int) followed by the letter "l"
. Maybe you intended "%lu"
(unsigned long) however both of those are incorrect for uint64_t
.
The proper specifier is found in inttypes.h
, and it is "%" PRIu64
.
Also this doesn't print 0x
as you suggested , it prints a decimal representation. Use "%" PRIx64
for hex representation (which also doesn't print the leading 0x
).
Moving on, your code causes undefined behaviour. According to the strict aliasing rule, it is not allowed to use an expression of type uint64_t
to access any variable that was not written as uint64_t
or int64_t
in the first place.
You can avoid the strict aliasing rule by using a variable of the correct type, either in a union or otherwise, e.g.:
uint64_t x;
memcpy(&x, a, sizeof x);
printf("%" PRIu64 "\n", x);
Your compiler will optimize this so don't worry about it being inefficient or something.
Note that the output of this is implementation-defined as the compiler could choose various ways of ordering the bits of a uint64_t
. Two common orders are big-endian and little-endian.
The other part of your question is about other integer types. Unfortunately you're stuck with what your compiler provided. Most likely it didn't offer uint94_t
. You'll have to roll your own code to achieve what you want. For example you could simulate 96-bit big endian:
uint8_t a[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C};
uint64_t x = 0, y = 0;
mempcy((unsigned char *)&x + 4, a, 4);
memcpy(&y, a+4, 8);
printf("%" PRIx64 "%" PRIx64 "\n", x, y);
Of course you could just print it character by character.