Reputation: 155
For example,
struct node {
struct node *left, *right;
};
#define LEFT(X) (X->left)
#define RIGHT(X) (X->right)
I would like to forbid macro call like this without changing the existing macro interface.
LEFT(n) = ...
Any idea?
Upvotes: 7
Views: 469
Reputation: 507105
For C++, I would use unary +:
#define LEFT(X) (+((X)->left))
#define RIGHT(X) (+((X)->right))
For a general macro case, this has the advantage over adding +0
that it also works for void*
and function pointers. For C, you can use the comma operator
#define LEFT(X) (0, ((X)->left))
#define RIGHT(X) (0, ((X)->right))
Upvotes: 1
Reputation: 214275
You don't write "accessor" macros like that, you do
typedef struct
{
...
} X;
X x;
#define LEFT (x.y.z.left)
Then you access the LEFT macro like any other variable. This makes the code more readable while at the same time effectively disabling the whole unsafe, ugly-looking, error prone, undefined-behavior ballet associated with function-like macros.
Upvotes: 0
Reputation: 78943
I'd just go for an explicit cast
#define LEFT(X) ((struct node*)(X->left))
#define RIGHT(X) ((struct node*)(X->right))
the result of such a cast is always an rvalue. If in addition you don't want to allow to change what the pointers are pointing to add a const
as was already given in another answer:
#define LEFT(X) ((struct node const*)(X->left))
#define RIGHT(X) ((struct node const*)(X->right))
Upvotes: 0
Reputation: 215387
Try this:
#define LEFT(X) ((X)->left+0)
#define RIGHT(X) ((X)->right+0)
Upvotes: 8
Reputation: 208406
You can use the ternary operator to force the result of the macro to be an rvalue, but the error message might be confusing to users:
struct node {
node *left, *right;
};
#define LEFT( x ) ( true ? (x).left : (node*)0 )
int main() {
node n;
// LEFT( n ); // error
node *l = LEFT( n ); // OK
}
The trickery there is in the semantics of that specific operator. The type of the expression containing just the operator is a common type (or a type convertible from) of the two branches of the expression, even if only one of them is ever evaluated. Now, when the compiler evaluates true ? x.left : (node*)0
it resolves to the expression x.left
but with the common type of x.left
and (node*)0
. Both of them are basically the same type, with the only detail that (node*)0
is an rvalue, rather than a lvalue.
Upvotes: 3
Reputation: 52314
I'd go with the inline function, but if you want a macro:
#define LEFT(X) (1 ? (X)->left : 0)
Upvotes: 5
Reputation: 46981
Maybe const
, though it requires an explicit type:
#define LEFT(X) ((const struct node *) (X->left))
...though if you have the typeof
compiler extension:
#define LEFT(X) ((const typeof(X->left)) (X->left))
Upvotes: 1
Reputation: 1077
I don't think there is any way of preventing that. Probably the best way would be not to use macros.
Upvotes: 3
Reputation: 26995
#undef LEFT
#undef RIGHT
//template<class T>
inline const node * const LEFT(const node * X) {
return X->left;
}
Upvotes: 6