class 或函数声明中间的宏

Macros in the middle of a class or function declaration

我已经阅读了 this and this 等相关问题和其他页面,但它们并没有真正回答我的问题。

基本上,我看到如下代码。

class SOME_MACRO SomeClass{
    SomeClass();
    ~SomeClass();
};

这让我很困惑。现在我认为自己对 C++ 相当了解(尽管对预处理器了解较少),但我不记得在我读过的任何书中看到过这样的声明。然而,我一直在现实世界中看到这样的代码,例如在 OpenCV 中。你在书上或在class中学到的C++和你在实践中实际看到的C++之间似乎存在差异,我觉得这很不幸。

我从 here and here that macros like that above are used to tell the linker how to link it properly, or something like that. For the example here 那里了解到,QuickFAST_Export 会变成 __declspec(dllexport)__declspec(dllimport)。在其他情况下,这些宏会告诉链接器如何根据系统是 Linux 还是 Windows 进行操作。我从抽象的角度了解这一切;我知道宏的用途,我知道它们现在的作用,至少大致如此。所以我不想要像 "those macros are there so you can change the [...]" 这样的答案,因为这些答案没有告诉我我自己如何在我可能从头开始编写的程序中使用这种声明。

我的问题是,什么时候将 __declspec(dllimport) 之类的内容放在 class 声明的中间是合法的? __declspec(dllimport) 是什么东西?一个int?一个东西?在 C++ 标准的哪一部分中说这样的 class 声明是合法的?如果有人可以编写一个最小的程序来说明中间有一个非平凡(非空)宏的 class 声明,编译并最好做一些可见的事情,那将不胜感激。

规范没有指定如何 link 一个程序一起或到外部库,或构建库,或者坦率地说与 linker 有关的任何事情,除了哪些符号在整个过程中可见翻译单位。

实现是自由的,并负责实现他们想要的所有方式,甚至通过语言扩展。任何带有两个下划线的东西都是实现分配的。因此,关于那里发生的一切都是合法的,你不会在规范中的任何地方找到它。

对于标识符,相邻的下划线(例如 __attribute____declspec)和前导下划线后跟大写字符(例如 _Bool_Thread_local)是(通常) 保留供编译器将来使用和使用。这意味着正常的语言规则不适用于您的示例,因为编译器可以自由扩展语言。 (C.f. "What are the rules about using an underscore in a C++ identifier?")

看看 GCC 庞大的语言扩展列表:https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions

并且输入实际上仅在 预处理之后才被解析。 SOME_MACRO 也可以包含 X; class 它会带来的所有好处。

__declspec(dllimport)

您可以设置多种类型的属性和说明符,具体取决于您在做什么、使用的编译器、目标操作系统等等。大多数人学习的不是针对特定的编译器,而是每个人都支持的核心 C++/C 标准。

I've learnt from here and here that macros like that above are used to tell the linker how to link it properly, or something like that.

迂腐地说,告诉 linker 如何 link 的并不是 。宏被预处理器简单地替换为它被定义为替换的任何文本。对于您的示例,它将有条件地替换为 __declspec(dllexport)__declspec(dllimport)。另一方面,那些 declspec 说明符确实会告诉 linker 该做什么……至少有一些 linker 理解说明符。

since when was it legal to just put something like __declspec(dllimport) in the middle of a class declaration anyway?

自从微软实现了他们的编译器并指定它是合法的。根据 c++ 标准,这是不合法的。

In which part of the C++ standard does it say that class declarations like this are legal?

没有。使用这些说明符是非标准的,并且不能保证在 Microsoft 以外的任何其他编译器中工作。这就是为什么当在不支持该关键字的编译器中使用时,此类宏通常被定义为扩展为空字符串(或者可能是其他特定于另一个实现的东西)。

What actual thing is __declspec(dllimport)?

非标准关键字。您可以从他们的 (Microsoft) documentation.

了解更多信息

为了更深入一点,关键字告诉 linker 在编译共享(动态 linked)库时如何导出符号。动态 linking 是一个完全不符合标准的概念。它是实现定义的。

how I might go about using this kind of declaration myself, in a program that I might write from scratch, myself.

你打算写一个共享库吗?如果不是,那么你不需要知道。如果是,那么您需要阅读您所针对的每个平台的文档。

这是 Microsoft 文档中的 walkthrough,可指导您完成创建动态 linked 库的步骤。