Defining Global Constant in C++

Defining global constants in C

Use in the header

extern const u32 g_my_const;

In this case this will be only a declaration of the constant and in the c module there will be its definition.

#include "header.h"
const u32 g_my_const= 10U;

As it was already mentioned in a comment by @Thomas Jager to your question you can use standard aliases for types by means of including the header <stdint.h>

For example

#include <stdint.h>

extern const uint32_t g_my_const;

Defining global constants in C++1z?

Summary

In C++17, the easiest way to define a global constant or a global variable is usually with an inline variable. You create one by simply putting a line like the following into your header file:

inline const std::string greeting = "Hello!";

If the global constant is of literal type, prefer using inline constexpr (the inline is optional if it’s a static class member) instead of inline const:

inline constexpr std::string_view greeting = "Hello!"sv;

This also works for variables, but many of the advantages no longer apply, so you might want to use another method:

inline unsigned int score = 0;

Details

First, the two main disadvantages to this method are:

  1. It doesn’t work before C++17, so if you need C++14 compatibility or earlier, you’ll need to do something else. The template trick VTT suggests is compatible with older standards, and should have similar semantics to inline variables, but it’s a hack which is no longer necessary if you only need C++17 support.
  2. It is somewhat slower to compile than extern variables, because the compiler needs to consolidate the multiple definitions, and because more information is available to the optimizer. The “somewhat” part turns into a “noticeably” if you might change the definition, but not the data type; since the value is now in a header file, this means recompiling everything that includes the header, instead of just re-linking. If you might need to change the data type everything will need to be recompiled no matter what.

If neither of those is important to you, I think this method beats the other ways of getting a global constant with external linkage and at most¹ one definition in the final executable².

An inline variable like this is mentioned in just one file, so it’s easy to change; this is particularly useful for header-only libraries. This also means it has its value available at compile time, so the optimizer can see it and maybe eliminate some usages.

Using constexpr

In C++17, static constexpr class members are automatically inline, so if your global constant should be part of a class’s scope, you can do something like

constexpr int favorite_number = -3;

Otherwise, you will need to say constexpr inline, which should still work. This will have the semantics described above, but also the usual advantages of constexpr, so the compiler will know that it can try to do more at compile time. For example:

#include <string_view>

using namespace std::literals;

inline constexpr std::string_view greeting = "Hello!"sv;

inline constexpr int scrabble_points[greeting.size()] = {4, 1, 1, 1, 1, 0};

int main() {
int total = 0;
for (int i : scrabble_points) {
total += i;
}
return total;
}

is possible with constexpr, but not with just inline, because with constexpr it knows that greeting.size() is a compile-time constant and can be used as the size of an array.³ With optimizations, this could compile to a just a single mov instruction and ret, without including any copies of the string or array because it’s unnecessary.

With the new inline semantics, everything before main could have been in a header file included in multiple places, and there would still have been at most one copy.

Variables

The same method easily supports mutable variables by leaving off the const:

inline std::string player_name = "<subject name here>";

This is then a global variable with external linkage. Since it’s a variable, most of the advantages I’v mentioned over Pete’s answer are gone, but some (like only declaring the variable in one place and not needing to link any thing extra) are still present. They might not be worth the slight extra compile time and the lack of C++14 compatibility, though.


¹ For a const or constexpr variable, the compiler/optimizer might completely eliminate the variable if it isn’t needed. In theory, it might decide to copy it to an immediate value or something; in practice you probably shouldn’t worry about that because it would only do that if it had a good reason, and this should make the final executable smaller and/or faster. You could probably tune this with -Os instead of -O3.

² Each object file which used the constant would still have a copy, but those would be combined at link time. The only way to avoid that is with extern variables.

³ This simplified example works even without inline, or with the array being only const instead of constexpr, but those are useful for more complicated real-world situations.

How to declare a global const variable and initialize it with a function in C?

How to declare a global const variable and initialize it with a function in C?

There is no way. It is not possible.

Is there any simple, portable way to solve my problem?

No.

You can use a macro #define MY_FUNCTION() (42).

You can write a separate program, that uses that C function (or is written in a completely different language), that generates C source code with that constant and that generated source code is then compiled with your project.

Or you can switch to a different programming language with more features, for example Rust, D, C++.

Defining global constant in C++

(5) says exactly what you want to say. Plus it lets the compiler optimize it away most of the time. (6) on the other hand won't let the compiler ever optimize it away because the compiler doesn't know if you'll change it eventually or not.

#define vs const global

Unless you use the & address-of operator on var1, the compiler is not obliged to give it a fixed address. (Although it probably will, if the variable is defined with external linkage.)

Even if you do take var1s address, the compiler is entitled to substitute a reference to the variable with its known value. So there is no real difference at runtime between the two ways of defining constants.

During the compilation, there is a difference: var2 can be used where the compiler requires a constant, such as a case label or array size, whereas var1 cannot. That has no performance implications, but it might still be a consideration.

Also, integer literals -- if they are used -- must be stored somewhere, even if it is an immediate operand of a machine instruction. Whether that is feasible and beneficial depends on the size of the integer and the machine architecture. It does not depend on whether the constant has a name.

Proper way to create global constant C strings

When you create a global constant variable in the header, then that variable never actually gets committed to memory.

What happens instead is that any code that uses that variable simply replaces any reference with "single msg".

This means there is no need use extern, but in turn does mean you must always include that header if you use the variable.

What extern is actually used for is exposing a variable that has been declared in a .cpp file, and therefore is in memory somewhere, to other cpp files. This is only necessary if you want a global but dynamic variable.

How to initialize global constant variable in main() function using pure C?

I need global parameters gained from main() and they must be constants.

No portable way to do directly as OP wants.

Code needs different access for reading and writing. Effectively hiding the access to the true data.


A close solution it to set and get data via functions defined in another file. Then no way to change data once set and only settable once.

main_var.h

int main_var_get(void);
void main_var_set(int v);

main_var.c

#include <stdlib.h>
#include "main_var.h"

static int var; // This could instead be a struct of many members.
// Or a pointer to a struct with many members.
static int var_init;

int main_var_get(void) {
if (!var_init) {
// Handle call of get before set, perhaps exit or return default value
exit(EXIT_FAILURE);
}
return var;
}

void main_var_set(int v) {
if (var_init) {
// Handle 2nd set, perhaps exit or ignore
exit(EXIT_FAILURE);
}
var = v;
var_init = 1;
}

main.c

#include <stdio.h>
#include "main_var.h"

int main(void) {
main_var_set(42);
...
printf("%d\n", main_var_get());
}

Another is to use a const int *. Access before setting is the same no-no as dereferencing NULL. Attempting to write *main_var_addr is UB like writing any const object.

main_var.h

extern const int *main_var_addr;
void main_var_set(int v);

main_var.c

#include <stdlib.h>
#include "main_var.h"

const int *main_var_addr = NULL;
static int var;

void main_var_set(int v) {
if (main_var_addr) {
// Handle 2nd set attempt, perhaps exit or ignore
exit(EXIT_FAILURE);
}
var = v;
main_var_addr = &var
}

main.c

#include <stdio.h>
#include "main_var.h"

int main(void) {
main_var_set(42);
...
printf("%d\n", *main_var_addr);
}


Related Topics



Leave a reply



Submit