1

I have seen header file code something like this:

#ifndef GS
#define GS

struct GS gs {
public:
    int n;
    gs(int n) : n{ n } {}
};

#endif // !GS

What is the purpose of using GS in struct GS gs? The code works exactly the same if I remove it.

I am pretty new to C++. I tried to search this on google without success.

Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
  • Related: [Header file included only once in entire program?](https://stackoverflow.com/q/30873206/514235) – iammilind Jan 20 '19 at 14:29
  • 1
    In the code you show, there's no point. Where did you see this pattern? – Some programmer dude Jan 20 '19 at 14:29
  • On a side-note, when you use `struct` in C++ it's the same as a `class`. The difference is that by default the visibility of a `struct` already is `public` (as opposed to a `class` where it's `private`). That means you don't need that `public:` in the structure. – Some programmer dude Jan 20 '19 at 14:30
  • @Someprogrammerdude - I saw it the libtorrent code [here](https://github.com/arvidn/libtorrent/blob/5018d91bb8454aa732dedb2e14da181c16b04ce0/include/libtorrent/storage.hpp#L157). It seems it's used at many places – Gurwinder Singh Jan 20 '19 at 14:32
  • 1
    @GurwinderSingh that's a different thing. TORRENT_EXPORT is probably defined as dllexport or dllimport which are reserved keywords that tells the compiler if the method is available outside the .dll or not. Search for "declspec". – AlexG Jan 20 '19 at 14:33
  • If you look at the top of that linked header file (which should be part of the question body really) then you will see that the header-guard macros is `TORRENT_STORAGE_HPP_INCLUDE`. Try doing a search for `TORRENT_EXPORT` in the projects header files to find its definition, and you will see what it really does. – Some programmer dude Jan 20 '19 at 14:33
  • @Someprogrammerdude - It's defined [here](https://github.com/arvidn/libtorrent/blob/5018d91bb8454aa732dedb2e14da181c16b04ce0/include/libtorrent/aux_/export.hpp#L84) But can't seem to find any special treatment of it. – Gurwinder Singh Jan 20 '19 at 14:36
  • 1
    That's *one* place of definition. But note how it's guarded with an `#ifndef`? On some platforms and compilers (typically on Windows) it might already be defined to something else. Widen your search. As mentioned by @AlexG, it's probably defined as `__declspec(dllexport)` or `__declspec(dllimport)` or similar (depending on if the header files are used for creating a DLL or not). – Some programmer dude Jan 20 '19 at 14:40
  • 1
    @GurwinderSingh The definition on lines 88-90 is a "catch-all" definition that makes the code correct if the symbol wasn't already set in lines 68-72 or earlier. – molbdnilo Jan 20 '19 at 14:41
  • 2
    @GurwinderSingh It'll be defined somewhere else as part of build scripts that might define TORRENT_EXPORT as an argument when running the compiler, depending on the compiler and operating system it's cocompiled on, it'll mark the struct to be exported when build ing a .dll .You should rather ask about this specific code in libtorrent rather than your made up example - it'll be much clearer to people what that specific purpose is. – nos Jan 20 '19 at 14:43
  • 1
    The more relevant lines are 68-72 where `TORRENT_EXPORT` is defined as `BOOST_SYMBOL_EXPORT` or `BOOST_SYMBOL_IMPORT` depending on wheter the header file is used in an application using the library or when building the library itself. And as @Someprogrammerdude already pointed out expands to `__declspec(dllexport)` or `__attribute__((visibility("default")))`. – Swordfish Jan 20 '19 at 14:44

4 Answers4

3

You are right that there is no change in the behavior of the code. There is no apparent benefit from the code you show.

This is because

#define GS

Defines GS as nothing, so after the preprocessor finishes, there is no difference from not including it in the declaration of the struct.

struct gs {

What could be the reason would be if there is some other tool that reads the code before the preprocessor and marks some kind of usage.

Note: in the comments, you reference other code. That code may, depending on other flags, set the macro to something, such as BOOST_SYMBOL_EXPORT. That then may have specific meaning. These kinds of usage are often used for marking classes as export or import depending on what the compiler is doing at the time.

crashmstr
  • 28,043
  • 9
  • 61
  • 79
1

Base on your comment your refer to this:

struct TORRENT_EXPORT storage_interface {
}

Where TORRENT_EXPORT might be defined as #define TORRENT_EXPORT

These kind of macros are use to enable system/compile/environment dependent options.

In case of TORRENT_EXPORT to enable the export of the symbols if it should be use as dynamic linke library:

#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

Or can be used for other pre or post processing scripts as markers to find the definitions easier. (e.g. to create API documentations, to create glue APIs to scripting languages, ...)

In other cases it is used to enable language features only if the compiler supports it (like constexpr)

t.niese
  • 39,256
  • 9
  • 74
  • 101
0

The only visible benefit for such code is to make sure that the macro is used for the purpose of guards and nothing else, even accidentally.
See below scenario:

// 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

Modern compilers will give warning for re-define of a macro.

Nevertheless, such guard doesn't harm in anyway and provides a little benefit to avoid any accidental redefinition.
Usually modern IDE-s will create the guard in a unique way, which includes the file extension with extra underscores _ such as:

#ifndef GS_H_
#define GS_H_

Hence, such extra check may not be required, because any developer wouldn't tend to create the file-like macros.

iammilind
  • 68,093
  • 33
  • 169
  • 336
0

A purpose of a macro is that it is replaced by something else (whatever that macro is defined to be) by the pre processor.

Specifically, placing a macro between class-key and the class name (such as in your example), will let the macro control the attribute sequence of the class. For example, if you define the macro to be empty (such as in your example), then the class will have an empty attribute sequence:

#define GS
struct GS gs {
// same as
struct gs {

But a macro can be defined to be non-empty:

#define GS alignas(8)
struct GS gs {
// same as
struct alignas(8) gs {

Macros can be passed as an argument to the tool chain upon compilation, thereby toggling a feature on or off. Macros can also be used to detect the target system and thereby enable system specific code - thereby allowing a system dependent program work on multiple systems.


Another purpose of a macro is to prevent a header from being included twice. Such macro is called a header guard. Using the same macro for both a header guard, and content replacement (such as in your example) is confusing and unconventional.

eerorika
  • 232,697
  • 12
  • 197
  • 326