What do these macros do?
Asked Answered
D

3

5

I have inherited some heavily obfuscated and poorly written PIC code to modify. There are two macros here:

#define TopByteInt(v) (*(((unsigned char *)(&v)+1)))
#define BottomByteInt(v) (*((unsigned char *)(&v)))

Is anyone able to explain what on earth they do and what that means please?

Thanks :)

Decollate answered 26/8, 2014 at 11:14 Comment(7)
They are macros to fetch the top and bottom byte half of a 16 bit integer typeEndamage
If you can't decode these simple expressions then you are going to have trouble with more complicated code... which bit of it is unclear?Farkas
The "poorly written" part is mostly the useless parenthesis while a required (for some arguments) pair is missing: #define TopByteInt(v) (*((unsigned char *)&(v) + 1)) would be better...Nonna
@MattMcNabb, I've been writing embedded code for over twenty years and have no difficulty in writing clear, easy-to-follow, well structured code. Which this is not.Decollate
@malso, I wasn't necessarily saying these macros were poorly written, just I could not fathom what they meant. Although, having had it explained to me, I think it's a bizarre way of writing it.Decollate
Many thanks to all for the explanations.Decollate
You've never seen aliasing a value of one type as another type?Farkas
B
1
(*((unsigned char *)(&v)))

It casts the v (a 16 bit integer) into a char (8 bits), doing this you get only the bottom byte.

(*(((unsigned char *)(&v)+1)))

This is the same but it gets the address of v and sum 1 byte, so it gets only the top byte.

It'll only work as expected if v is a 16 bits integer.

Basophil answered 26/8, 2014 at 11:19 Comment(3)
Huh? The first macro clearly uses &v too, it doesn't "cast the integer".Licensee
Yes, you're right, it gets the first 8 bits portion stored in the address of v, that would be more precise.Basophil
I like this explanation the best as it points out that the "+1" is accessing the next byte. That's a salient point I was not seeing. Thank you.Decollate
L
5

They access a 16-bit integer variable one byte at a time, allowing access to the most significant and least significant byte halves. Little-endian byte order is assumed.

Usage would be like this:

uint16_t v = 0xcafe;
const uint8_t v_high = TopByteInt(&v);
const uint8_t v_low  = BottomByteInt(&v);

The above would result in v_high being 0xca and v_low being 0xfe.

It's rather scary code, it would be cleaner to just do this arithmetically:

#define TopByteInt(v)    (((v) >> 8) & 0xff)
#define BottomByteInt(v) ((v) & 0xff)
Licensee answered 26/8, 2014 at 11:16 Comment(3)
PIC is a 8-bit microcontroller and maybe it was written in order to avoid unneccessary shiftsPiegari
Your way is how I'd write it, only I'd not use bloomin' macros!Decollate
@Decollate Me neither, probably, but it's handy to stay close to the original question some times.Licensee
B
1
(*((unsigned char *)(&v)))

It casts the v (a 16 bit integer) into a char (8 bits), doing this you get only the bottom byte.

(*(((unsigned char *)(&v)+1)))

This is the same but it gets the address of v and sum 1 byte, so it gets only the top byte.

It'll only work as expected if v is a 16 bits integer.

Basophil answered 26/8, 2014 at 11:19 Comment(3)
Huh? The first macro clearly uses &v too, it doesn't "cast the integer".Licensee
Yes, you're right, it gets the first 8 bits portion stored in the address of v, that would be more precise.Basophil
I like this explanation the best as it points out that the "+1" is accessing the next byte. That's a salient point I was not seeing. Thank you.Decollate
C
1

Ugg.

Assuming you are on a little-endian platform, that looks like it might meaningfully be recorded as

#define TopByteInt(v) (((v) >> 8) & 0xff)
#define BottomByteInt(v) ((v) & 0xff)

It is basically taking the variable v, and extracting the least significant byte (BottomByteInt) and the next more significant byte (TopByteInt) from that. 'TopByte' is a bit of a misnomer if v isn't a 16 bit value.

Cordero answered 26/8, 2014 at 11:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.