Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this macro statement legal C++ or something else? And if it is legal how does it work

WebKit has a lot of pre-processor lines like this: #if MACRO1(MACRO2)

For example:

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

So my first thought was that they were function-like macros, but I can't see how that would work, and I couldn't find any #defines for these macros anywhere in the source code.

I asked another engineer what it was and he's never seen multiple macros used like that inside a #if before either. I found this wiki page that talks about them but it still wasn't clear to me where they come from,

So my question then: Is this valid C++ or is it being replaced in the code by another tool/language like CMake or something else, and if it is valid C++ is there a spec anyone is aware of that talks about this?

I'm a support engineer for a C++ Static Analysis tool that isn't handling this syntax. A customer asked us to handle it, but if I'm going to take this to the senior engineer I'd like to not sound like an idiot :) So I'd like the nitty gritty if anyone knows it.

like image 868
Tradsud Avatar asked Jul 29 '11 23:07

Tradsud


2 Answers

As mentioned in the wiki, in root/trunk/Source/JavaScriptCore/wtf/Platform.h we get a definition for each of these defines. For instance, the PLATFORM macro is defined as:

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

The value of WTF_FEATURE will be replaced by the platform name to create some macro named WTF_PLATFORM_WTF_FEATRE. For instance, with WTF_FEATURE passed into the macro as MAC, you would end up with a expansion of WTF_PLATFORM_MAC. The pre-processor defined directive combined with the logical AND is basically asking whether that macro value defined, and if it is defined, if its value is a "true" value. You would use this macro somewhere else in the pre-processor like:

#ifdef __APPLE__
#define WTF_PLATFORM_MAC 1
#end if

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

#if PLATFORM(MAC)
//...some code
#end if

You wouldn't use it within C++ code itself like

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

that would cause a bunch of errors from the compiler since defined is not a C++ keyword, and the evaluation and replacement of the macro within C++ code would end up dumping the defined pre-processor directive into any C++ code that directly called the macro. That's not valid C++.

Thanks you to Johannes for pointing out some of these issues.

like image 188
Jason Avatar answered Sep 28 '22 07:09

Jason


The #if directive roughly works by replacing all macros, and then replacing all identifier and keywords of what's left by 0 and afterwards processing what's left has a constant expression according to the rules of the C++ language (the subset of those rules applicable to what's left from that replacing - quite little :)).

So PLATFORM(MAC) may yield a 1 if MAC is defined to be 1, and a MAC if it is not defined, if PLATFORM is simply defined as

#define PLATFORM(X) X

The resulting MAC is an identifier and will later be replaced by 0. It's more likely that they are concatenating the X to something like PLATFORM, so as to support multiple queries with MAC as argument, testing for existence of different macros. As a developer of a " C++ Static Analysis" tool you probably have access to the C++ spec. Take a look at clause 16.1.

like image 45
Johannes Schaub - litb Avatar answered Sep 28 '22 07:09

Johannes Schaub - litb