例如,
struct node {
struct node *left, *right;
};
#define LEFT(X) (X->left)
#define RIGHT(X) (X->right)
我想在不改变现有宏接口的情况下禁止这样的宏调用。
LEFT(n) = ...
有什么想法吗?
答案 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宏。这使代码更具可读性,同时有效地禁用与类函数宏相关的整个不安全,丑陋,易出错,未定义的行为芭蕾。