Macro Expansion

This bug made me spent half of my day. I have a macro to read a 32-bit data from either a virtual memory or RAM, depending on the address passed to a macro. More or less the code is as follow


#define read_u32(addr)    (if (is_addr_in_virtual(addr))?read_virtual_u32(addr):(*((u32 *) addr )) )

Did you see what is wrong?

Normally the macro works fine, let say we have a “ram_addr” which is an address in RAM and we pass it to the macro


var = read_u32(ram_addr)

//read_u32(ram_addr) will return 
var = (*((u32 *) ram_addr))


The problem happen when parameter passed is some short of operation like “base_addr + offset” where the macro expansion leads to a different behavior than expected.


var = read_u32(ram_addr + offset)

//read_u32(ram_addr + offset) will return
var = (*((u32 *) ram_addr + offset)

Let’s say that ram_addr is 0x0000A00 and offset is 2. What I want the macro to return is the u32 data in address 0x0000A02. But the expansion above, will return address 0x0000A08 since “ram_addr” is casted to (u32 *) before adding to “offset”.

The problem lies on the presence of parenthesis surrounding the macro parameter. The corrected version is as follow.

 
#define read_u32(addr)    (if (is_addr_in_virtual(addr))?read_virtual_u32(addr):(*((u32 *) (addr) )) ) 

This way, if I pass “ram_addr + offset” to the macro, the addition will take place first before the address is casted to (u32 *), and thus will return correct value.