我正在研究的程序有很多适用于所有类的常量.我想制作一个头文件"Constants.h",并能够声明所有相关的常量.然后在我的其他课程中,我可以包括#include "Constants.h.
我使用#ifndef... #define ...语法使其工作正常.但是,我更喜欢使用const int...常量的形式.我不太清楚如何.
bam*_*s53 76
您只需const ints在头文件中定义一系列:
// Constants.h
#if !defined(MYLIB_CONSTANTS_H)
#define MYLIB_CONSTANTS_H 1
const int a = 100;
const int b = 0x7f;
#endif
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为在C++中,名称空间范围(包括全局命名空间)的名称显式声明为const而未显式声明为extern具有内部链接,因此当您将翻译单元链接在一起时,这些变量不会导致重复的符号.或者,您可以将常量显式声明为静态.
static const int a = 100;
static const int b = 0x7f;
Run Code Online (Sandbox Code Playgroud)
这与C更兼容,对于可能不熟悉C++链接规则的人来说更具可读性.
如果所有常量都是整数,那么您可以使用的另一种方法是将标识符声明为枚举.
enum mylib_constants {
a = 100;
b = 0x7f;
};
Run Code Online (Sandbox Code Playgroud)
所有这些方法仅使用标头,并允许声明的名称用作编译时常量.使用extern const int和单独的实现文件可防止名称用作编译时常量.
需要注意的是,使某些常量规则隐含内在联系也适用于指针,酷似其它类型的常量.但棘手的是,将指针标记为const需要与大多数人用来制作其他类型const变量的语法略有不同.你需要这样做:
int * const ptr;
Run Code Online (Sandbox Code Playgroud)
制作一个常量指针,以便规则适用于它.
还要注意,这是我更喜欢const在类型之后持续放置的一个原因:int const而不是const int.我还把*下一个变量:即int *ptr;代替int* ptr;.
我喜欢做这些事情,因为它们反映了C++真正起作用的一般情况.替代方案(const int,int* p)只是特别容易使一些简单的东西更具可读性.问题在于,当你走出这些简单的案例时,特殊的套装替代品会变得有误导.
因此,虽然前面的例子显示了常见的用法const,但我实际上会建议人们像这样写:
int const a = 100;
int const b = 0x7f;
Run Code Online (Sandbox Code Playgroud)
和
static int const a = 100;
static int const b = 0x7f;
Run Code Online (Sandbox Code Playgroud)
Man*_*san 26
为了这种目的,我更喜欢命名空间.
选项1 :
#ifndef MYLIB_CONSTANTS_H
#define MYLIB_CONSTANTS_H
// File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils
namespace LibConstants
{
const int CurlTimeOut = 0xFF; // Just some example
...
}
#endif
// source.cpp
#include <LibConstants.hpp>
int value = LibConstants::CurlTimeOut;
Run Code Online (Sandbox Code Playgroud)
选项2:
#ifndef MYLIB_CONSTANTS_H
#define MYLIB_CONSTANTS_H
// File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils
namespace CurlConstants
{
const int CurlTimeOut = 0xFF; // Just some example
...
}
namespace MySQLConstants
{
const int DBPoolSize = 0xFF; // Just some example
...
}
#endif
// source.cpp
#include <LibConstants.hpp>
int value = CurlConstants::CurlTimeOut;
int val2 = MySQLConstants::DBPoolSize;
Run Code Online (Sandbox Code Playgroud)
而且我永远不会使用Class来保存这种类型的HardCoded Const变量.
Som*_*ude 12
const int如果它包含在多个源文件中,通常不应该在头文件中使用eg .那是因为变量将在每个源文件中定义一次(从技术上讲是翻译单位),因为全局const变量是隐式静态的,占用的内存比所需的多.
您应该有一个特殊的源文件,Constants.cpp它实际上定义了变量,然后将变量声明为extern头文件中的变量.
像这个头文件的东西:
// Protect against multiple inclusions in the same source file
#ifndef CONSTANTS_H
#define CONSTANTS_H
extern const int CONSTANT_1;
#endif
Run Code Online (Sandbox Code Playgroud)
这在源文件中:
const int CONSTANT_1 = 123;
Run Code Online (Sandbox Code Playgroud)
C++17 inline variables
This awesome C++17 feature allow us to:
constexpr: How to declare constexpr extern?main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
Run Code Online (Sandbox Code Playgroud)
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
Run Code Online (Sandbox Code Playgroud)
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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.
C++17 standard draft on "global" const implies static
This is the quote for what was mentioned at: /sf/answers/843023891/
C++17 n4659 standard draft 6.5 "Program and linkage":
3 A name having namespace scope (6.3.6) has internal linkage if it is the name of
- (3.1) — a variable, function or function template that is explicitly declared static; or,
- (3.2) — a non-inline variable of non-volatile const-qualified type that is neither explicitly declared extern nor previously declared to have external linkage; or
- (3.3) — a data member of an anonymous union.
"namespace" scope is what we colloquially often refer to as "global".
Annex C (informative) Compatibility, C.1.2 Clause 6: "basic concepts" gives the rationale why this was changed from C:
6.5 [also 10.1.7]
Change: A name of file scope that is explicitly declared const, and not explicitly declared extern, has internal linkage, while in C it would have external linkage.
Rationale: Because const objects may be used as values during translation in C++, this feature urges programmers to provide an explicit initializer for each const object. This feature allows the user to put const objects in source files that are included in more than one translation unit.
Effect on original feature: Change to semantics of well-defined feature.
Difficulty of converting: Semantic transformation.
How widely used: Seldom.
See also: Why does const imply internal linkage in C++, when it doesn't in C?
Tested in GCC 7.4.0, Ubuntu 18.04.