2

Let's say I have this:

uint8_t a[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

If I:

printf("%lu", ((uint64_t*) a)[0]);

I'll get:

0x0102030405060708

How can I do this with a non-standard size? ex. ((uint94_t) a)[0]. Of course, there is no uint94_t and that's what I'm asking. How to read a non-standard number of bits (or even bytes, it does the job for me as well)?

Note: I don't care for printf's specific string (so it can parse non-standard amount of bit/bytes) but in the datatype

dzervas
  • 250
  • 2
  • 14

2 Answers2

2

"%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.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
0

A little bit of googling got me the answer... The answer is bitfields!

typedef union {
    __uint128_t i : 96;
} __attribute__((packed)) uint96_t;
printf("%ul", ((uint96_t*) a)[0]);
dzervas
  • 250
  • 2
  • 14
  • 1
    note: This causes undefined behaviour, also it's unlikely to produce 96 bits worth of output, try making `a` have 12 bytes as in my last example – M.M Dec 26 '15 at 06:15