Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any trick to forbid C macro to be called as a lvalue?

Tags:

c

macros

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?

like image 854
wsxiaoys Avatar asked Apr 15 '11 11:04

wsxiaoys


People also ask

Which is faster macro or function?

The speed at which macros and functions differs. Macros are typically faster than functions as they don't involve actual function call overhead.

How to define a macro function in C?

A macro is a fragment of code that is given a name. You can define a macro in C using the #define preprocessor directive. Here's an example. Here, when we use c in our program, it is replaced with 299792458 .

Why to use macros in C?

In C, the macro is used to define any constant value or any variable with its value in the entire program that will be replaced by this macro name, where macro contains the set of code that will be called when the macro name is used in the program.

Why macro used in place of a function?

Speed versus size The main benefit of using macros is faster execution time. During preprocessing, a macro is expanded (replaced by its definition) inline each time it is used. A function definition occurs only once regardless of how many times it is called.


7 Answers

Try this:

#define LEFT(X) ((X)->left+0)
#define RIGHT(X) ((X)->right+0)
like image 200
R.. GitHub STOP HELPING ICE Avatar answered Oct 18 '22 05:10

R.. GitHub STOP HELPING ICE


#undef LEFT
#undef RIGHT

//template<class T>
inline const node * const LEFT(const node * X) {
    return X->left;
}
like image 39
Alexey Malistov Avatar answered Oct 18 '22 05:10

Alexey Malistov


I'd go with the inline function, but if you want a macro:

#define LEFT(X) (1 ? (X)->left : 0)
like image 31
AProgrammer Avatar answered Oct 18 '22 05:10

AProgrammer


I don't think there is any way of preventing that. Probably the best way would be not to use macros.

like image 24
ColWhi Avatar answered Oct 18 '22 06:10

ColWhi


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.

like image 28
David Rodríguez - dribeas Avatar answered Oct 18 '22 04:10

David Rodríguez - dribeas


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))
like image 23
aib Avatar answered Oct 18 '22 06:10

aib


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))
like image 32
Johannes Schaub - litb Avatar answered Oct 18 '22 04:10

Johannes Schaub - litb