2011-07-29 11 views
6

WebKit tiene una gran cantidad de líneas pre-procesador como este: #if MACRO1(MACRO2)¿Es esta macro declaración legal C++ o algo más? Y si es legal, ¿cómo funciona

Por ejemplo:

#if PLATFORM(MAC) || (PLATFORM(QT) && USE(QTKIT)) 
#include "MediaPlayerPrivateQTKit.h" 
#if USE(AVFOUNDATION) 
#include "MediaPlayerPrivateAVFoundationObjC.h" 
#endif 
... 

Así que lo primero que pensé fue que estaban función similar macros, pero no veo cómo funcionaría eso, y no pude encontrar #defines para estas macros en ninguna parte del código fuente.

Le pregunté a otro ingeniero qué era y nunca antes ha visto varias macros utilizadas así dentro de un #if. Encontré este wiki page que habla de ellos pero todavía no estaba claro para mí de dónde vienen,

Entonces mi pregunta es: ¿Es esto C++ válido o está siendo reemplazado en el código por otra herramienta/lenguaje como CMake u otra cosa, y si es válida C++, ¿hay alguna especificación de la que todos sepan que habla al respecto?

Soy ingeniero de soporte para una herramienta de Análisis estático de C++ que no maneja esta sintaxis. Un cliente nos pidió que lo manejáramos, pero si voy a llevar esto al ingeniero principal, me gustaría no sonar como un idiota :) Así que me gustaría saber si alguien lo sabe.

+4

Dice allí mismo en la página wiki que publicó el enlace que esas macros están definidas en 'Platform.h', ¿buscó ese archivo? –

+0

Técnicamente legal o no, si se compila con algún compilador que admita y un cliente con suficiente influencia lo quiere, debe considerar apoyarlo de todos modos, al menos detrás de una bandera en tiempo de ejecución, posiblemente incluso si está macro-d en CMake o algo mas. Si se trata de CMake-d, entonces podría volver a enviarlo al cliente para que haga que CMake genere el código real que se compila y luego lo analice de forma estática. – Rup

+0

@John bien puede ser generado por los scripts de compilación y no en el proceso de finalización de la fuente. Tradsud, ¿realmente has intentado construir WebKit para ver qué hace? – Rup

Respuesta

5

Como se menciona en la wiki, en root/trunk/Source/JavaScriptCore/wtf/Platform.h obtenemos una definición para cada uno de estos define. Por ejemplo, la macro PLATFORM se define como:

#define PLATFORM(WTF_FEATURE) \ 
     (defined WTF_PLATFORM_##WTF_FEATURE \ 
     && WTF_PLATFORM_##WTF_FEATURE) 

El valor de WTF_FEATURE será reemplazado por el nombre de la plataforma para crear algo de macro llamado WTF_PLATFORM_WTF_FEATRE.Por ejemplo, con WTF_FEATURE pasado a la macro como MAC, terminaría con una expansión de WTF_PLATFORM_MAC. La directiva preprocesador defined combinada con el AND lógico básicamente pregunta si ese valor macro definido, y si está definido, si su valor es un valor "verdadero". Se podría utilizar esta macro en otro lugar en el pre-procesador como:

que no se usará dentro de código C++ sí mismo como

if (PLATFORM(MAC)) 
{ 
    //...some code 
} 

que causaría un montón de errores del compilador desde defined no es una palabra clave C++, y la evaluación y el reemplazo de la macro dentro del código C++ terminarían volcando la directiva del preprocesador defined en cualquier código C++ que llamara directamente a la macro. Eso no es válido C++.

Gracias a Johannes por señalar algunos de estos problemas.

+1

Weird. La especificación dice "Si el token * definido * se genera como resultado de este proceso de reemplazo o si el uso del operador unario definido no coincide con una de las dos formas especificadas antes de la sustitución de macro, el comportamiento no está definido". ¿Eso significa que el código tiene un comportamiento indefinido? O estoy malinterpretando esto. –

+0

A menos que vea algo incorrecto, no parece que * defined * se está generando como resultado del proceso de reemplazo que tiene lugar dentro de la macro ... me parece que se está aplicando como unario operador ... por lo tanto, básicamente se dice que 'WTF_PLATFORM _ ## WTF_FEATURE' debe ser algo que se define tanto * como * y se evalúa con un valor distinto de cero. – Jason

+0

@litb: después de que se produzca la sustitución de macro, el resultado estará bien formado mientras peguen juntos lo que 'WTF_PLATFORM' y' WTF_FEATURE' resuelven a es un identificador. Entonces tendrías 'define some_identifier', que es una de las dos formas especificadas. –

0

Las definiciones pueden provenir de los scripts de compilación. La mayoría de los compiladores de C++ le permiten definir macros en la línea de comando.

Una forma puedo ver a definir una macro del uso como en su ejemplo sería:

#define USE_QTKIT 1 
#define USE(x) USE_ ## x 

O tal como:

gcc -DUSE_QTKIT=1 '-DUSE(x)=USE_ ## x' 
3

La directiva #if funciona más o menos mediante la sustitución de todas las macros, y luego reemplaza todos los identificadores y palabras clave de lo que queda por 0 y luego el procesamiento de lo que queda tiene una expresión constante según las reglas del lenguaje C++ (el subconjunto de esas reglas aplicables a lo que queda de eso reemplazando - bastante poco :)).

Así PLATFORM(MAC) puede producir un 1 si MAC se define como 1, y una MAC si no se define, si PLATFORM se define simplemente como

#define PLATFORM(X) X 

El resultante MAC es un identificador y posteriormente se reemplazado por 0. Es más probable que concatenan el X a algo así como PLATFORM, para admitir múltiples consultas con MAC como argumento, probando la existencia de diferentes macros. Como desarrollador de una herramienta de "Análisis estático de C++", probablemente tenga acceso a las especificaciones de C++. Eche un vistazo a la cláusula 16.1.

+0

+1 para sus dos últimas oraciones (aunque fue mejor pre-editar). – ildjarn

+0

+1 ... gracias por señalar los errores en mi respuesta – Jason

Cuestiones relacionadas