【问题标题】:Is this macro statement legal C++ or something else? And if it is legal how does it work这个宏语句是合法的 C++ 还是其他东西?如果它是合法的,它是如何工作的
【发布时间】:2011-07-29 23:10:59
【问题描述】:

WebKit 有很多这样的预处理器行: #if MACRO1(MACRO2)

例如:

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

所以我的第一个想法是它们是类似函数的宏,但我看不出它是如何工作的,而且我在源代码的任何地方都找不到这些宏的任何#defines。

我问过另一位工程师它是什么,他也从未见过在 #if 中使用多个宏。 我发现了这个wiki page 谈论他们,但我仍然不清楚他们来自哪里,

那么我的问题是:这是有效的 C++,还是在代码中被 CMake 或其他工具/语言等其他工具/语言替换,如果它是有效的 C++,是否有任何人知道有关此的规范?

我是不处理此语法的 C++ 静态分析工具的支持工程师。一位客户要求我们处理它,但如果我要把它交给高级工程师,我不想听起来像个白痴:) 所以如果有人知道的话,我想了解一下细节。

【问题讨论】:

  • 它在您发布链接的 wiki 页面上说,这些宏在 Platform.h 中定义,您是否查找该文件?
  • 技术上是否合法,如果它使用您支持的某个编译器构建,并且有足够影响力的客户想要它,那么您无论如何都应该考虑支持它,至少在运行时标志后面,可能即使它是由 CMake 或其他东西在宏中进行的。如果是 CMake-d,那么您可以将其推回给客户,让他们让 CMake 生成实际编译的代码,然后进行静态分析?
  • @John 它很可能是由构建脚本生成的,而不是在源代码签出中生成的。 Tradsud,你真的尝试过构建 WebKit 来看看它的作用吗?
  • 看起来很合法:ideone.com/osJuG.

标签: c++ macros webkit c-preprocessor


【解决方案1】:

正如 wiki 中提到的,在 root/trunk/Source/JavaScriptCore/wtf/Platform.h 中,我们得到了每个定义的定义。例如,PLATFORM 宏定义为:

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

WTF_FEATURE 的值将替换为平台名称以创建一些名为 WTF_PLATFORM_WTF_FEATRE 的宏。例如,将WTF_FEATURE 作为MAC 传递到宏中,您最终会得到WTF_PLATFORM_MAC 的扩展。预处理器defined 指令与逻辑AND 相结合基本上是询问是否定义了该宏值,如果已定义,它的值是否为“真”值。你可以在预处理器的其他地方使用这个宏,比如:

#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

你不会像在 C++ 代码中那样使用它

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

由于defined 不是 C++ 关键字,这将导致编译器出现一堆错误,并且在 C++ 代码中对宏的求值和替换最终会将 defined 预处理器指令转储到任何 C++ 代码中那直接调用宏。这不是有效的 C++。

感谢 Johannes 指出其中一些问题。

【讨论】:

  • 很奇怪。规范说“如果令牌 defined 是由于此替换过程或使用定义的一元运算符与宏替换之前的两种指定形式之一不匹配,则行为未定义。 ”。这是否意味着代码具有未定义的行为?还是我看错了。
  • 除非我发现有问题,否则它看起来不像 defined 是由于宏内发生替换过程而生成的......它看起来我喜欢它被用作一元运算符......所以它基本上是说WTF_PLATFORM_##WTF_FEATURE 必须是既定义了并且计算为非零值的东西。
  • @litb:宏替换发生后,只要将WTF_PLATFORM 和WTF_FEATURE 解析为标识符的任何内容粘贴在一起,结果就会是正确的。然后你会得到define some_identifier,这是两种指定形式之一。
  • @Michael 我们应该有defined some_identifier,但这是未定义的行为,因为defined 令牌是宏替换的结果。
  • 好的,我知道争论的焦点在哪里......我相信这个宏应该在预处理器中使用......也就是说,它会像#if PLATFORM(X) ... #end if一样使用
【解决方案2】:

#if 指令的大致工作原理是替换所有宏,然后用0 替换剩下的所有标识符和关键字,然后根据 C++ 语言的规则处理剩下的具有常量表达式(的子集)这些规则适用于替换后剩下的内容-很少:))。

所以如果MAC 被定义为1,PLATFORM(MAC) 可能会产生一个1,如果没有定义,如果PLATFORM 被简单地定义为一个MAC,则可能会产生一个PLATFORM

#define PLATFORM(X) X

生成的MAC 是一个标识符,稍后将替换为0。他们更有可能将X连接到PLATFORM之类的东西,以支持以MAC为参数的多个查询,测试不同宏的存在。作为“C++ 静态分析”工具的开发人员,您可能有权访问 C++ 规范。看一下子句16.1。

【讨论】:

  • 最后两句话+1(虽然它是更好的预编辑)。
【解决方案3】:

定义可能来自构建脚本。大多数 C++ 编译器允许您在命令行上定义宏。

我可以看到在您的示例中定义 USE 宏的一​​种方法是:

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

或者可能是这样的:

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

【讨论】:

    猜你喜欢
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    相关资源
    最近更新 更多