Summary of constant definitions in C++

  • 2020-04-02 03:17:29
  • OfStack

This note is summarized from a code review.

Generally speaking, when programming in C language, we are used to using the macro definition in C to define a numerical constant:


#define MY_CONST 7

In C++ development projects, the use of constants in C is also common. As a result, one of the following ways of writing seems a bit unorthodox:


class MyClass {
  static const int my_const = 7;

  // ...
};

From a compiler's point of view, both of these are legal, but you have to choose between them. Which is more appropriate? I've heard before that you should use as few c-style macro definitions as possible in C++. Why?

After looking up some data, it is found that the main reasons for reducing the macro definition in C are as follows:

Macros are prone to errors when defining functions. It is recommended to use inline instead of macro functions.

When macros define constants, they perform text substitution in the preprocessing process, and do not generate corresponding symbols during compilation, which is not conducive to debugging. Therefore, it is recommended to use const or enum to define constants in C++.

There are two ways to define a constant in C++ : using static const and enum. Such as:


class MyClass {
  static const int my_const = 7;
  enum {another_const = 7};

  // ...
};

For both ways, there is a little bit more to it. When using const to define a constant in a class, you must make it static and declare it outside of the class definition. This is not necessarily the case for enum, so Bjane Stroustrup in his FAQ suggests using enum to define constants.

All in all, there are many ways to define the in-class constant in C++, and the three methods mentioned above are available. When writing a private project, of course, you can use whatever you want, depending on your personal preference. It is more desirable to follow the code specifications advocated by the team when working as a member of the development team. In this case, I prefer the definition method of enum, and I will choose to capitalize all the constants :)


class MyClass {
  enum {MY_CONST = 7}; 
 
  // ...
};

We often define some constants in the common header file.

Method 1

H (common header file) :


const int constname = XXX;

#include "commdef.h" where the variable is used

Method 2
H (common header file) :


extern const int constname;

Commdef. CPP file:


const int constname = XXX;

#include "commdef.h" where the variable is used
Because both compile and run fine, programmers rarely notice the difference. Comparison of the two methods:

If you add or remove constants, it is more convenient to use method 1. You only need to modify it in the. H file. If you change the constant value, the program using method 2 does not need to change the header file, which will save compilation time.

Which is better in terms of memory usage? Let's test it out.

The test program defines two modules, test1 and test2, test1.cpp and test2.cpp both refer to commdef.

Environment: Windows + vs2005


//Commdef. H file

#ifndef LX_COMMDEF_H
#define LX_COMMDEF_H
const int MAX_LENGTH = 1024;
extern const int MIN_LENGTH;
#endif

//Commdef. CPP file

#include "commdef.h"
const int MIN_LENGTH = 10;
//Test1. CPP file (note: header content omitted for simplicity)
#include "commdef.h"
#include "test1.h"
#include <iostream>
using namespace std;
void FuncTest1()
{
 cout << "MAX_LENGTH = " << MAX_LENGTH << ", address: " << &MAX_LENGTH << endl;
 cout << "MIN_LENGTH = " << MIN_LENGTH << ", address: " << &MIN_LENGTH << endl;
}

//Test2. CPP file (note: header content omitted for simplicity)

#include "commdef.h"
#include "test1.h"
#include <iostream>
using namespace std;
void FuncTest2()
{
 cout << "MAX_LENGTH = " << MAX_LENGTH << ", address: " << &MAX_LENGTH << endl;
 cout << "MIN_LENGTH = " << MIN_LENGTH << ", address: " << &MIN_LENGTH << endl;
}

Output:

MAX_LENGTH = 1024, address: 00437AE4
MIN_LENGTH = 10, address: 00437B54
MAX_LENGTH = 1024, address: 00437B1C
MIN_LENGTH = 10, address: 00437B54

As you can see, the constants defined with method 1 are stored separately in multiple modules, and the constants defined with method 2 are stored in one place, so method 2 is superior to method 1 in terms of storage.

Especially when there are many constants and header files that are referenced, it is important to note that improper definition can lead to unnecessary memory waste.

Conclusion:

1. No type specified
#define does not involve type checking for defined constants. To explicitly specify a constant type, you need to suffix a constant. For example, for constants of type float, add an f suffix to the number.

2. No scope is specified
The constants defined by #define are global.

3. No access control
You can't mark a constant defined by #define as public, protected, or private, it's essentially public.
Because once a macro is defined, it is valid for subsequent compilation (unless it is #undef somewhere).

4. No sign
In the previous example, the macro MAX_NUM_SIZE may be stripped from the code by the preprocessor so that the compiler cannot see the name. In this way, the programmer can only see constant values without any description when debugging.


Related articles: