2011-02-27 15 views
33

consideran este código:MSVC no se expande __VA_ARGS__ correctamente

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ 
#define G(...) F(__VA_ARGS__) 
F(1, 2, 3) 
G(1, 2, 3) 

El resultado esperado es X = 1 and VA_ARGS = 2, 3 tanto para las macros, y eso es lo que estoy haciendo con GCC, sin embargo, MSVC expande esto como:

X = 1 and VA_ARGS = 2, 3 
X = 1, 2, 3 and VA_ARGS = 

Es decir, __VA_ARGS__ se expande como un único argumento, en lugar de desglosarse en varios.

¿Hay alguna forma de evitar esto?

+6

Mi primer pensamiento sería obtener un mejor compilador. Si este es el primer error y el más serio que has encontrado en MSVC, te esperan MUCHAS sorpresas desagradables ... –

+1

@R: No es una opción: P – uj2

Respuesta

34

El preprocesador de MSVC parece comportarse de manera bastante diferente a la especificación estándar .
Probablemente la siguiente corrección ayudará a:

#define EXPAND(x) x 
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ 
#define G(...) EXPAND(F(__VA_ARGS__)) 
+0

'__VA_ARGS__' aún no es parte del estándar C++. ¿El borrador del estándar realmente especifica cuál debería ser el comportamiento en este caso? – bk1e

+1

@ bk1e: Lo siento, ya que no tengo la capacidad, no puedo explicar el preproceso en el próximo estándar C++ en detalle aquí, pero es poco probable que sea bastante diferente de C99. –

+1

¿Podría alguien explicar esto? ¿Es "y VA_ARGS = __VA_ARGS__" una pieza válida de código C o es solo un texto legible por humanos que está aquí como un comentario? si este es un código válido, ¿qué está haciendo "y VA_ARGS = __VA_ARGS__"? Gracias. – Virus721

16

I publicado the following Microsoft support issue:

El siguiente programa da error de compilación porque el precompilador expande __VA_ARGS__ incorrectamente:

#include <stdio.h> 

#define A2(a1, a2) ((a1)+(a2)) 

#define A_VA(...) A2(__VA_ARGS__) 

int main(int argc, char *argv[]) 
{ 
    printf("%d\n", A_VA(1, 2)); 
    return 0; 
} 

Los expande preprocesador el printf a: printf ("% d \ n", ((1, 2) +()));

en lugar de printf ("% d \ n", ((1) + (2)));

que recibió la siguiente respuesta insatisfactoria de un desarrollador del equipo compilador de Microsoft:

Hola: El compilador de Visual C++ se comporta correctamente en este caso. Si combina la regla de que los tokens que coinciden con el '...' en la invocación de macro inicial se combinan para formar una sola entidad (16.3/p12) con la regla de que las sub-macros se expanden antes del reemplazo del argumento (16.3.1/p1) entonces, en este caso, el compilador cree que A2 se invoca con un único argumento: de ahí el mensaje de error.

+1

Gracias por pasar a lo largo de la lógica de MS. Parece que están interpretando "combinados para formar un solo elemento" en 16.3.1/p12 como "combinados para formar un token de preprocesador permanentemente indivisible", lo que parece ser menos útil. Esperaría que los tokens sustituidos sean reseparados al menos para el paso de reescaneo en 16.3.4, que parece ser lo que otros compiladores están haciendo. – jcl

+0

Estoy totalmente de acuerdo, pero estoy evidentemente mimado por GCC y Clang. ¿Alguno de ustedes puede pensar en un caso de uso para el comportamiento de MSVC, o es solo una cuestión de coherencia por coherencia a pesar de la expresividad? Estoy fuera de mi elemento, pero "... en este caso, el compilador * cree * ..." no suena muy convincente, y mucho menos útil para cualquiera que intente escribir código agnóstico. Tengo algunas ideas para soluciones temporales, pero mi partición de Windows está fuera de servicio. Me gustaría ver que alguien lo intente en cualquier caso. Perdón por la diatriba y/o necropost. –

+1

FWIW, aquí hay [otro error] (https://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement) sobre el mismo problema, donde el equipo admite que es un error, pero dice que no es No tiene la prioridad suficiente para arreglar (hace 7 años). – BeeOnRope

1

¿Qué versión de MSVC estás utilizando? Necesitará Visual C++ 2010.

__VA_ARGS__ fue presentado por primera vez por C99. MSVC nunca intentó admitir C99, por lo que no se agregó el soporte.

Ahora, sin embargo, __VA_ARGS__ está incluido en el nuevo estándar de C++, C++ 2011 (anteriormente conocido como C++ 0x), que Microsoft aparentemente planea admitir, por lo que ha sido admitido en versiones recientes de MSVC.

Por cierto, tendrá que usar un sufijo .cpp en su archivo fuente para obtener este soporte. MSVC no ha actualizado su interfaz C durante mucho tiempo.

Cuestiones relacionadas