Provide locally scoped identifers. More...
Go to the source code of this file.
Macros | |
#define | __LOC(POS0, POS1) |
refer to an identifier created with __LOC_NEW | |
#define | __LOC_NEW |
create a new identifier in the current scope of {} | |
Provide locally scoped identifers.
This provides two macros __LOC and __LOC_NEW that expand and manage identifiers that are unique within the current set of curly braces {}
. (For using another prefix than __LOC, see below.)
Note that here __LOC needs parenthesis for the invokation and receives 0, 1, or 2 arguments. The above expands to something similar as the following
Obivously here the concrete names that are chosen depend on the context where this code would be found. You should not try to recover such names manually.
The first argument to __LOC indicates to which of the unique idenfier it refers: 0, the default, refers to the last identifer created with __LOC_NEW
(here the variable initialized with the value 6
), 1 to the one before (here the variable initialized with the value 5
).
So the above example should print the values 6 5
in that order.
Curly braces add a hierarchical aspect, namely nesting levels for identifiers. To see that consider a macro SWAPEM(A, B)
with the following expansion:
Here {
moves one "level" up in the hierarchy of identifiers. To see that in context let's amend our example from above by adding an invokation of SWAPEM
.
The expansion would be looking similar to the following:
So here the expansion of the three lines that we had before has not changed at all; in the printf
call we can easily refer to the identifiers as we did before without needing to worry about what effects the invokation of SWAPEM
might have caused.
In contrast to that the call to SWAPEM
itself sees a new set of names for its variables, here identifiers starting with __LOC_ID_2_
, and so the variables defined there are in no conflict with the identifiers in the surrounding scope.
As a result of this invokation, the contents of the two variables is swapped and the two values would be 5 6
, inverted compared to what we had seen above.
__LOC has an optional second parameter that refers to the level in which the identifier is sought. As for the first paremeter, 0
, the default, refers to the current level, 1
refers to one level down and so on.
Typically you would include this feature with a directive such as
This provides you with a set of macros as described above that have names starting with __LOC.
#define __LOC | ( | POS0, | |
POS1 | |||
) |
refer to an identifier created with __LOC_NEW
POS0 | is the "distance" to the invocation of __LOC_NEW: 0 refers to the latest, 1 to the one before and so on. |
POS1 | refers to the level of curly braces of the referred identifier, 0 is the current level, 1 is one level up and so on. |
Let's see this with an example:
Here, we create three variables, but in different scopes. Inside the function body, the two parameters are referred by __LOC(1, 1)
and __LOC(0, 1)
because they are the before last and last defined names in the scope outside the {}
of the function body (therefore the second argument 1
for both). The variable declared inside the body is referred by __LOC(0, 0)
(or __LOC(0)
or __LOC()
), with a 0
as second parameter referring to the current level of {}
.
The above example will be replaced by something like the following.
All three identifiers will be unique in the whole translation unit, and thus will not conflict with anything else.
Another use case for __LOC_NEW
would be parameters in function prototypes, for which you want to avoid that they ever conflict with user defined identifiers.
Not that here the second an third parameters have no names; we don't need them so we omit them. In contrast to that the first parameter conveys information about the type of the two others and is used for their definition. After expansion this looks similar to the following
using an identifier that is guaranteed not to be in conflict with any other identifier of the translation unit and that we just don't want to have to invent ourselves.
#define __LOC_NEW |
create a new identifier in the current scope of {}
struct
or union
types that you provide in headers, eve of those that you want to hide from the user. These would get instantiated differently in different translation units, and thus types would not be compatible across translation units.