In a header I was looking at, I saw this...
... is that valid? I don't recall seeing a macro like that before.Code:#define MMM_X(x)_Z(z) (0x0C + (((x)-1)*3 + ((z)-1))*4)
In a header I was looking at, I saw this...
... is that valid? I don't recall seeing a macro like that before.Code:#define MMM_X(x)_Z(z) (0x0C + (((x)-1)*3 + ((z)-1))*4)
Looks strange, I've never seen anything like that, actualy... Does it compile?
--
Mats
Why not use 12 instead of 0x0C? I've never understood why people use hex when decimal is simpler. Yeah, that does look weird.
What on earth is that supposed to do?
"No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
"Have you tried turning it off and on again?" - The IT Crowd
That ain't right whatever it is. Even if _Z(x) was another macro that did something, it looks malformed. And if it does do something it needs to be rewritten free of stupid so we know what the hell is going on.
> Why not use 12 instead of 0x0C? I've never understood why people use hex when decimal is simpler.
Some people are nerds. There are uses for hex values though (it can be convenient if you're talking about bits or colors), but don't mix radices like that.
I may be a nerd, but to me, there's really no difference between hex or decimal, but of course, it's not particularly easy to translate 0x1267 to 4711 decimal to me either. But common numbers such as 0x0C or 0x100, 0x200, 0xFFFF, I don't see a problem with.
There are different reasons to use one or another. In this case, perhaps the 0x0C is a register/offset/other-constant defined as 0x0C by some documentation?
--
Mats
The kernel build completes without error.Does it compile?
As I said in the original post, it is part of a kernel header, a large one, in which dozens of register values are defined, bit masks and other offsets. All of these are in hex. If I convert this line to decimal, I will be adding a source of error, since it will be assumed to be 0x12 to a non-careful reader.Why not use 12 instead of 0x0C?
What "the hell" is going on, is at a base address, begins a list of registers, (in an ARM9 processor), dedicated to a particular function. At offset 0x0C, a repeating structure begins whereby there are 5 sets of 3 registers dedicated to subchannels in an on chip communications controller, or at least, that is what the macro is trying to do.we know what the hell is going on.
Thus, assuming a 0x00 start address and port 1 register 1...
MMM_X(1)_Z(1);Code:#define MMM_X(x)_Z(z) (0x0C + (((x)-1)*3 + ((z)-1))*4)
(X-1)*3 = 0
(Z-1)*4 = 0
... therefore the address of port 1 register 1 is 0x00 + 0x0C + 0 + 0 i.e. 0x0C.
That is what I believe the designer of the header wishes to acheive, reading the datasheet of the chip, it certainly makes sense.
Regardless of the proclivity for embedded designers to work in hex, as we do, and the failure of GCC to complain, the question really remains the same. Is it legal?
I suspect not, but I tend to avoid the pre-processor and have done for years. I don't know for sure.
Last edited by Exit; 08-31-2007 at 09:11 AM. Reason: Spelling.
How about using "gcc -E" to output the preprocessed stuff and see what actually comes out?
--
Mats
It would be "clearer" if the missing space had been retained:
It's a macro of a single argument, x. _Z is presumably some other macro which reduces to a function name or function pointer.Code:#define MMM_X(x) _Z(z) (0x0C + (((x)-1)*3 + ((z)-1))*4)
Not particularly mysterious.
Apart from name changes to "protect the innocent" that is as it appears in the header, there is NO space in the macro definition.It would be "clearer" if the missing space had been retained:
Your explanation does, in no way, reflect the actual requirement. If what you are suggesting is correct, then the author is way off. Clearly, 2 arguments are necessary to return the correct register offset.
Last edited by Exit; 08-31-2007 at 02:53 PM.
I didn't say there was.
Someone's confused, but it's not me:Your explanation does, in no way, reflect the actual requirement. If what you are suggesting is correct, then the author is way off. Clearly, 2 arguments are necessary to return the correct register offset.
Which is nonsense. Unless of course there is a macro called _Z.Code:File mac1.c: #define MMM_X(x)_Z(z) (0x0C + (((x)-1)*3 + ((z)-1))*4) int main() { int x, z; MMM_X(1)_Z(2); } $ gcc -E mac1.c int main() { int x, z; _Z(z) (0x0C + (((1)-1)*3 + ((z)-1))*4)_Z(2); }
...I didn't say there was.
Your implication was that a space had been omitted - that is not the case.It would be "clearer" if the missing space had been retained:
Consider, also, the actual requirement, which I have detailed.
I have already stated that I believe the construct to be dubious, however, it does not alter the fact that it is in a kernel header applicable to my current project, indeed, I now need to modify these registers in that switch, hence my interest.
Ok, so given what brewbuck points out (which is that the macro does work correctly).
Put a simpler way, this is LEGAL, even if it's not pretty, and will expand as follows
becomesCode:#define a(x)y(x) int main() { a(7); ....
So, yes, it's legal and works correctly - I'm pretty sure other compilers will also work OK with this construction, not just GCC.Code:int main() { y(7); ....
However, I would insert a space there if I was modifying the file anyways.
--
Mats
so would it be right to conclude from this then that a closing bracket in a macro name delimits the end of that macro's name (and the start of its definition)? Interesting... can anyone confirm if this complies with the ISO99 definition of a C macro?
I have no idea about what the standard says, but yes, it makes some sense that it is that way - spaces are really only used to delimit things when there is NOTHING else to go by - you can certainly use other constructs without spaces when there is a different delimiter...
I don't think there's any way to "use" the fact that there's no space between the macro name and it's definition...
--
Mats