I was searching for driver code for SMC91C111 and came across some code in uboot. the following is a piece of code from that the smc91c111.h file. #define SMC_outb(d,r) ({ word __d = (byte)(d); \ word __w = SMC_inw((r)&~1); \ __w &= ((r)&1) ? 0x00FF : 0xFF00; \ __w |= ((r)&1) ? __d
It looks as if the underscores have been put there by the code's author to ensure that the (local) variable names don't conflict with other similar, single letter, variable names that might be present in application code.
You seem to have a particlarly ugly case of writing inline functions. The code on both functions is complicated enough to need an own function each.
In the SMC_inb() function, there is only a variable '__v', no variable called 'v'.
Probably, the purpose of the last statetment is to get the value of __v as the return value of the function.
The function finds the 16-bit word for the register at offset p in the SMC controller register block, reads the 16-bit register and splits the desired byte and returns it.
A function for similar use:
static unsigned char SMC_inb(int p) { volatile unsigned short *wordaddress; unsigned int value;
If you're using GCC, the effect of the original macro can be achieved by declaring the function above with the 'inline' qualifier (and it's much cleaner).
Similar considerations apply to the output function/macro.
It has none --- for starters because there *is* no variable named "p" nor "__p" in the above.
The __ has no significance of its own. It's not even a syntactical element of its own: it's just a part of the variable names "__d" and "__w", put there to avoid collisions of these names with variables used in functions that might invoke this macro. It's essentially a "no user-serviceable parts inside" sticker.
Frankly, if you don't understand this much of C, I don't think you should be messing around with system header files yet.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
That's not necessarily true. Remember this macro was found in a hardware-specific header file of Uboot. Uboot is infrastructure code, just like the OS on a more conventional hosted implementation. So its headers could justifiably be considered part of the C implementation for normal programs, which would allow it to use the reserved names.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
In C, identifiers beginning with two underscores or an underscore followed by a uppercase letter are reserved for the implementation (compiler), thus are not to be declared by the programmer. There are other reserved identifiers as well. This way the implementor can declare symbols guaranteed not to collide with user code which conforms to the standard.
That said, the above code uses a non-standard extension in which a bracketed list of statements is contained within an expression, which should make declared variables strictly local to the declaration, obviating the need for variables in the implementor's name space.
p is what the compiler will resolve each time the macro is "called". whereas __p is a stack allocated variable on the stack frame created by the macro. By watching the code it is clear that the variable __p is a copy of what p might be at compile-time.
There is NOTHING special about the underscores preceding the declared temp variable as Grant Edwards points out.
On 8 Sep 2005 22:15:33 -0700, "Anil" wrote in comp.arch.embedded:
Actually, the identifiers defined with leading double underscores in this macro, and the other macro you quote in another post, are absolutely unnecessary inclusions by someone whose understanding of the C language standard is somewhat weak.
As others have pointed out, all identifiers beginning with two underscores, or an underscore followed by an upper case letter, are reserved for the implementation. That means the compiler, its headers, and its libraries, not a 3rd party application like uboot, no matter how "system" it seems to be.
But regardless of whether or not uboot should be using identifiers of this pattern is rather immaterial, because they are absolutely unnecessary in this context.
Both macros open a block that contains their variable definitions and code. That block establishes its own scope, so if they happened to define a variable, say 'x', that exists in an outer scope, the 'x' defined inside the block completely hides the 'x' in the outer scope.
Wrong. For a macro like this, they're absolutely necessary to keep the macro universally usable. They avoid a name conflict between the actual macro argument and the variables created inside the macro body.
Which will explode nicely into your face as soon as somebody invokes the macros with the parameter being named 'x', too.
But all this is somewhat beside the point: those macros are 100% evil. Creating local variables inside a macro is a gold-plated invitation for nasty problems. This should really be done either in an inline function. Failing that (some compilers may not support inline), it should be re-written as a single-statement macro: no local variables, no strange compiler-specific extensions to allow a block to return a value.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Sorry, I can't agree with the 100% evil. They are simply the implementation for access functions in a custom header. Yes, they use extensions that aren't strictly required, but that's OK for a specific compiler+target, which this is. You might consider it an invitation, but nothing bad happens if you simply use the code as is. Its worse aspect, i think, is that it sets a poor example for the average Joe programmer peeking under the hood, but it works.
... until the day the makers of some (maybe: the) compiler for the platform this header is supposed to be used with decide to exercise the privilige granted to them by the standard and put
#define __p some very strange stuff here
in one of the system headers, or even make __p an inescapable predefined macro.
Basically, what those macros try to do is impossible to achieve in C. You unavoidably risk colliding either with user-space names, or with names reserved to the compiler. The latter adds causing undefined behaviour to the bill --- that's as close to 100% evil as you can possibly be and still get a compilable program.
It would be quite a bit more sensible to use prefixed names like "uboot__private_p" for such cases. Those are in user-land, so they avoid undefined behaviour. And if they ever do collide with the third-party code, you can plausibly deny responsibility for the consequences. You could even go ahead an put a phrase like "All identifiers beginning with uboot__ are belong to us!" in the documentation, to strengthen your case.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.