是否有任何技巧禁止C宏被称为左值?

时间:2011-04-15 11:11:27

标签: c macros

例如,

struct node {
  struct node *left, *right;
};
#define LEFT(X) (X->left)
#define RIGHT(X) (X->right)

我想在不改变现有宏接口的情况下禁止这样的宏调用。

LEFT(n) = ...

有什么想法吗?

9 个答案:

答案 0 :(得分:8)

试试这个:

#define LEFT(X) ((X)->left+0)
#define RIGHT(X) ((X)->right+0)

答案 1 :(得分:6)

#undef LEFT
#undef RIGHT

//template<class T>
inline const node * const LEFT(const node * X) {
    return X->left;
}

答案 2 :(得分:5)

我会使用内联函数,但如果你想要一个宏:

#define LEFT(X) (1 ? (X)->left : 0)

答案 3 :(得分:3)

我认为没有办法阻止这种情况。可能最好的方法是不使用宏。

答案 4 :(得分:3)

您可以使用三元运算符强制宏的结果为右值,但错误消息可能会让用户感到困惑:

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
}

那个特定运算符的语义就是诡计。仅包含运算符的表达式的类型是表达式的两个分支的公共类型(或可转换的类型),即使只评估其中一个。现在,当编译器评估true ? x.left : (node*)0时,它会解析为表达式x.left,但常用类型为x.left(node*)0。它们基本上都是相同的类型,唯一的细节是(node*)0是一个右值,而不是一个左值。

答案 5 :(得分:1)

也许const,虽然它需要一个明确的类型:

#define LEFT(X) ((const struct node *) (X->left))

...但是如果你有typeof编译器扩展名:

#define LEFT(X) ((const typeof(X->left)) (X->left))

答案 6 :(得分:1)

对于C ++,我会使用一元+:

#define LEFT(X) (+((X)->left))
#define RIGHT(X) (+((X)->right))

对于一般的宏案例,这比添加+0更有优势,它也适用于void*和函数指针。对于C,您可以使用逗号运算符

#define LEFT(X) (0, ((X)->left))
#define RIGHT(X) (0, ((X)->right))

答案 7 :(得分:0)

我只是去做一个明确的演员

#define LEFT(X) ((struct node*)(X->left))
#define RIGHT(X) ((struct node*)(X->right))

这种演员的结果总是一个左值。如果另外你不想允许更改指针指向的内容添加const,如另一个答案中已经给出的那样:

#define LEFT(X) ((struct node const*)(X->left))
#define RIGHT(X) ((struct node const*)(X->right))

答案 8 :(得分:0)

你没有这样写“访问者”宏,你做

typedef struct
{
  ...
} X;

X x;

#define LEFT (x.y.z.left)

然后像任何其他变量一样访问LEFT宏。这使代码更具可读性,同时有效地禁用与类函数宏相关的整个不安全,丑陋,易出错,未定义的行为芭蕾。