2011-04-15 12 views
7

Por ejemplo,¿Hay algún truco para prohibir que se llame macro C como valor a la izquierda?

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

quisiera prohibir llamada a la macro como esto sin cambiar la interfaz macro existente.

LEFT(n) = ... 

¿Alguna idea?

+0

¿Qué hace esa macro? No entiendo por qué alguna vez necesitarías una macro así. – Lundin

+0

@Lundin Lo tomo como ejemplo. para el código real hay muchos miembros con una estructura profunda, las macros de acceso serán útiles. – wsxiaoys

+0

@wsxiaoys Ok, ya veo. Publicaré una respuesta con un ejemplo de cómo debe hacer tales macros. – Lundin

Respuesta

8

Prueba esto:

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

Esto se ve como el más simple, pero no se puede optimizar como operador ternario, supongo. – wsxiaoys

+0

¡Guau! ... simple pero eficaz – BiGYaN

+0

@wsxiaoys: ¿Realmente no crees que una adición constante de '0' es más difícil que la poda de una rama que nunca se realiza? ¡Si algo es definitivamente más simple! –

6
#undef LEFT 
#undef RIGHT 

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

¿Para qué sirve el 'T'? – sharptooth

+0

Un poco smarmy, pero +1. El mejor consejo es no usar macros en absoluto. –

+0

con C++ no tiene macro ... – Petesh

3

no creo que hay alguna forma de evitar eso. Probablemente la mejor manera sería no usar macros.

+1

Esta es la solución adecuada al problema. – Lundin

1

Tal const, aunque requiere un tipo explícito:

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

... aunque si usted tiene la extensión typeof compilador:

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

Estos todavía son lvalues. OP está tratando de hacer que sea imposible editar el puntero, no los datos a los que apunta. –

5

me gustaría ir con la función en línea, pero si quiere una macro:

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

Puede usar el operador ternario para ce el resultado de la macro a ser un valor de lado derecho, pero el mensaje de error puede ser confuso para los usuarios:

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 
} 

El truco no está en la semántica de ese operador específico. El tipo de expresión que contiene solo el operador es un tipo común (o un tipo convertible desde) de las dos ramas de la expresión, incluso si solo una de ellas se evalúa alguna vez. Ahora, cuando el compilador evalúa true ? x.left : (node*)0, resuelve la expresión x.left pero con el tipo común de x.left y (node*)0. Ambos son básicamente del mismo tipo, con el único detalle de que (node*)0 es un valor r, en lugar de un valor l.

+0

O simplemente escribe 'node * l = n.left;' ... problema resuelto. – Lundin

0

me gustaría ir a por una conversión explícita

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

el resultado de un reparto tan es siempre un valor de lado derecho. Si además usted no desea permitir a cambiar lo que los punteros apuntan a añadir un const como ya se ha dado en otra respuesta:

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

Usted no escribe macros "descriptor de acceso" por el estilo, lo hace

typedef struct 
{ 
    ... 
} X; 

X x; 

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

A continuación, accede a la macro IZQUIERDA como cualquier otra variable. Esto hace que el código sea más legible y, al mismo tiempo, deshabilita de forma efectiva todo el ballet inseguro, de aspecto feo, propenso a errores, comportamiento indefinido asociado con macros funcionales.

1

para C++, me gustaría utilizar unario +:

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

Para un caso de macro general, esto tiene la ventaja sobre la adición de +0 que también trabaja para void* y función punteros.Para C, puede usar el operador de coma

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

En general, esto es mejor que mi respuesta ya que también funciona para 'void *'. Para el problema de OP realmente no importa. –

+0

@R .., tienes razón. Actualicé mi respuesta para ser más preciso :) –

+0

Finalmente, agregué '+ 0' en mi código porque al usar el operador de coma de esta manera genero una gran cantidad de" Expresión resultado no usado "advertencia – wsxiaoys

Cuestiones relacionadas