我已经看到头文件代码是这样的:
#ifndef GS
#define GS
struct GS gs {
public:
int n;
gs(int n) : n{ n } {}
};
#endif // !GS
在GS
中使用struct GS gs
的目的是什么?如果我将其删除,则代码的工作原理完全相同。
我对C ++很陌生。我试图在Google上搜索此搜索,但没有成功。
答案 0 :(得分:3)
您是对的,代码的行为没有改变。 您显示的代码没有明显好处。
这是因为
#define GS
将GS
定义为 ,因此,在预处理程序完成之后,与在结构的声明中不包括它没有区别。
struct gs {
可能的原因是,如果还有其他工具可以在预处理器之前读取代码并标记某种用法。
注意:在注释中,您引用其他代码。根据其他标志,该代码可以将宏设置为 something ,例如BOOST_SYMBOL_EXPORT
。那可能具有特定的含义。这些用法通常用于将类标记为导出或导入,具体取决于编译器当时的工作。
答案 1 :(得分:1)
根据您的评论,请参考以下内容:
struct TORRENT_EXPORT storage_interface {
}
TORRENT_EXPORT
可能被定义为#define TORRENT_EXPORT
这类宏用于启用系统/编译/环境相关的选项。
如果使用TORRENT_EXPORT
来启用符号导出(如果应将其用作动态链接库)
#if defined(_MSC_VER)
// Microsoft
#define TORRENT_EXPORT __declspec(dllexport)
#define TORRENT_IMPORT __declspec(dllimport)
#elif defined(__GNUC__)
// GCC
#define TORRENT_EXPORT __attribute__((visibility("default")))
#define TORRENT_IMPORT
#else
#define TORRENT_EXPORT
#define TORRENT_IMPORT
#pragma warning Unknown dynamic link import/export semantics.
#endif
或可用于其他预处理或后期处理脚本,作为标记,以更轻松地找到定义。 (例如,创建API文档,创建与脚本语言的粘合API等)
在其他情况下,仅当编译器支持语言功能时,它才用于启用语言功能(例如constexpr
)
答案 2 :(得分:0)
此类代码的唯一可见好处是确保将宏用于卫兵的目的,甚至是偶然使用。
请参见以下情形:
// file1.h
#define GS 1234
// file2.h
#ifndef GS
#define GS // defined for the guarding purpose
#include"file1.h" // "GS" re-defined for different purpose
// the redefinition will result in compiler error, due to adding guard in `struct` definition
struct GS gs { ... };
#endif
现代编译器会警告您重新定义宏。
尽管如此,这样的防护措施也不会造成任何损害,并且为避免意外重新定义提供了一点好处。
通常,现代IDE会以独特的方式创建防护,其中包括带有额外下划线_
的文件扩展名,例如:
#ifndef GS_H_
#define GS_H_
因此,可能不需要进行这种额外的检查,因为任何开发人员都不会倾向于创建类似文件的宏。
答案 3 :(得分:0)
宏的目的是由预处理器将其替换为其他任何东西(无论该宏定义为什么)。
具体来说,在类键和类名之间放置一个宏(例如在您的示例中),将使该宏控制类的属性序列。例如,如果您将宏定义为空(例如在您的示例中),则该类将具有空的属性序列:
case class Foo(id: String, `type`: String, color: String)
但是可以将宏定义为非空
#define GS
struct GS gs {
// same as
struct gs {
可以在编译时将宏作为参数传递给工具链,从而启用或禁用功能。宏还可以用于检测目标系统,从而启用系统特定的代码-从而允许依赖于系统的程序在多个系统上工作。
宏的另一个目的是防止头文件被两次包含。这样的宏称为标题保护。将相同的宏用作标头保护和内容替换(例如您的示例)既令人困惑又不合常规。