Defining global constant in C++

前端 未结 10 1901
梦如初夏
梦如初夏 2020-11-29 16:44

I want to define a constant in C++ to be visible in several source files. I can imagine the following ways to define it in a header file:

  1. #define GLOBAL_
10条回答
  •  萌比男神i
    2020-11-29 17:17

    C++17 inline variables

    This awesome C++17 feature allow us to:

    • conveniently use just a single memory address for each constant
    • store it as a constexpr: How to declare constexpr extern?
    • do it in a single line from one header

    main.cpp

    #include 
    
    #include "notmain.hpp"
    
    int main() {
        // Both files see the same memory address.
        assert(¬main_i == notmain_func());
        assert(notmain_i == 42);
    }
    

    notmain.hpp

    #ifndef NOTMAIN_HPP
    #define NOTMAIN_HPP
    
    inline constexpr int notmain_i = 42;
    
    const int* notmain_func();
    
    #endif
    

    notmain.cpp

    #include "notmain.hpp"
    
    const int* notmain_func() {
        return ¬main_i;
    }
    

    Compile and run:

    g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
    g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
    g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
    ./main
    

    GitHub upstream.

    See also: How do inline variables work?

    C++ standard on inline variables

    The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft 10.1.6 "The inline specifier":

    6 An inline function or variable with external linkage shall have the same address in all translation units.

    cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.

    Inline variable implementation

    We can observe how it is implemented with:

    nm main.o notmain.o
    

    which contains:

    main.o:
                     U _GLOBAL_OFFSET_TABLE_
                     U _Z12notmain_funcv
    0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
                     U __assert_fail
    0000000000000000 T main
    0000000000000000 u notmain_i
    
    notmain.o:
    0000000000000000 T _Z12notmain_funcv
    0000000000000000 u notmain_i
    

    and man nm says about u:

    "u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use.

    so we see that there is a dedicated ELF extension for this.

    Tested on GCC 7.4.0, Ubuntu 18.04.

提交回复
热议问题