2011-07-29 14 views
6

WebKit ha un sacco di linee pre-processore come questo: #if MACRO1(MACRO2)Questa istruzione macro è legale in C++ o qualcos'altro? E se è legale come funziona

Ad esempio:

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

Così il mio primo pensiero è stato che erano funzione simile macro, ma non riesco a vedere come funzionerebbe, e non ho trovato nessun #define per queste macro ovunque nel codice sorgente.

Ho chiesto a un altro ingegnere cosa fosse e non ha mai visto più macro utilizzate in un #if prima di entrambi. Ho trovato questo wiki page che parla di loro, ma non era ancora chiaro per me da dove vengono,

Quindi la mia domanda, allora: È questo valido C++ o è esso che è sostituito nel codice da un altro strumento/lingua come CMake o qualcos'altro, e se è valido C++ c'è una specifica che qualcuno è a conoscenza di ciò che parla di questo?

Sono un tecnico di supporto per uno strumento di analisi statica C++ che non sta gestendo questa sintassi. Un cliente ci ha chiesto di gestirlo, ma se ho intenzione di portarlo all'ingegnere anziano non mi piacerebbe sembrare un idiota :) Quindi mi piacerebbe il nocciolo duro se qualcuno lo sa.

+4

Dice proprio lì nella pagina wiki che hai postato il link per il fatto che quelle macro sono definite in 'Platform.h', hai cercato quel file? –

+0

Tecnicamente legale o no, se si costruisce con un compilatore che si supporta e un cliente con un peso sufficiente lo vuole, allora si dovrebbe prendere in considerazione di supportarlo comunque, almeno dietro un flag di runtime, forse anche se è macro-d in da CMake o qualcos'altro. Se è CMake-d in poi, potresti spingerlo indietro al cliente per convincerli a fare in modo che CMake generi il codice vero e proprio che viene compilato, quindi analizzarlo statico? – Rup

+0

@John potrebbe essere generato dagli script di compilazione e non nel controllo dell'origine. Tradsud, hai davvero provato a costruire WebKit per vedere cosa fa? – Rup

risposta

5

Come menzionato nella wiki, in root/trunk/Source/JavaScriptCore/wtf/Platform.h otteniamo una definizione per ciascuna di queste definizioni. Per esempio, la macro PLATFORM è definito come:

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

Il valore di WTF_FEATURE sarà sostituito dal nome della piattaforma per creare un po 'di macro denominata WTF_PLATFORM_WTF_FEATRE.Ad esempio, con WTF_FEATURE passato nella macro come MAC, si otterrebbe un'espansione di WTF_PLATFORM_MAC. La direttiva defined del preprocessore combinata con la logica AND sta essenzialmente chiedendo se il valore della macro è definito e, se è definito, se il suo valore è un valore "vero". Si potrebbe utilizzare questa macro da qualche altra parte nel pre-processor come:

Tu non utilizzare entro codice C++ se stesso come

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

che causerebbe un mucchio di errori dal compilatore dal defined non è una parola chiave C++ e la valutazione e la sostituzione della macro all'interno del codice C++ finiscono per scaricare la direttiva pre-processore defined in qualsiasi codice C++ che abbia chiamato direttamente la macro. C++ non valido.

Grazie a Johannes per aver segnalato alcuni di questi problemi.

+1

Strano. La specifica dice "Se il token * definito * viene generato come risultato di questo processo di sostituzione o l'uso dell'operatore definito unario non corrisponde a uno dei due moduli specificati prima della sostituzione della macro, il comportamento non è definito.". Significa che il codice ha un comportamento indefinito? O sto fraintendendo questo. –

+0

A meno che non stia vedendo qualcosa di sbagliato, non sembra che * definito * venga generato come risultato del processo di sostituzione che avviene all'interno della macro ... mi sembra come se fosse applicato come operatore unario ... quindi in pratica si dice che 'WTF_PLATFORM _ ## WTF_FEATURE' deve essere qualcosa che sia definito * e * valuti a un valore diverso da zero. – Jason

+0

@litb: dopo la sostituzione della macro, il risultato sarà ben formato fino a quando incollare insieme qualunque sia la risoluzione "WTF_PLATFORM' e" WTF_FEATURE' è un identificatore. Quindi dovresti 'define some_identifier', che è uno dei due moduli specificati. –

0

Le definizioni potrebbero provenire dagli script di compilazione. La maggior parte dei compilatori C++ consente di definire macro sulla riga di comando.

Un modo che posso vedere per definire una macro UTILIZZO come nel tuo esempio potrebbe essere:

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

O forse come:

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

La direttiva #if funziona grosso modo, sostituendo tutte le macro, e quindi sostituendo tutti gli identificatori e le parole chiave di ciò che è rimasto da 0 e successivamente elaborando ciò che è rimasto ha un'espressione costante in base alle regole del linguaggio C++ (il sottoinsieme di quelle regole applicabili a ciò che è rimasto da quella sostituzione - piuttosto poco :)).

Così PLATFORM(MAC) può produrre un 1 se MAC è definito come 1, e un MAC se non è definita, se PLATFORM è semplicemente definito come

#define PLATFORM(X) X 

Il risultante MAC è un identificatore e saranno successivamente sostituito da 0. È più probabile che concatenino lo X a qualcosa come PLATFORM, in modo da supportare più query con MAC come argomento, verificando l'esistenza di diverse macro. Come sviluppatore di uno strumento "Analisi statica C++" probabilmente hai accesso alle specifiche C++. Dai un'occhiata alla clausola 16.1.

+0

+1 per le ultime due frasi (anche se era meglio pre-modificare). – ildjarn

+0

+1 ... grazie per aver segnalato gli errori nella mia risposta – Jason

Problemi correlati