I googled const + extern on the internet, but it seems there isn't really a good answer for my question.
const alone means internal linkage, but if I want to share a const variable among compilation units. Is extern the best choice?
Common solution would be:
//g.h
extern const int MAX;
// g.c
extern const int MAX = 3;
However, this solution has a drawback, like below:
// Say, I want to use this MAX in the same header file.
// g.h
extern const int MAX;
class AClass
{
public:
AClass (): i(MAX){}
private:
int i;
};
Compiler will complain like:"error C2057: expected constant expression".
Is there a solution for this?
if you want to be able to use your constant at compile time (i.e. size an array by it, without using VLA) it has to be known at compile time, i.e. it cannot have external linkage.
However, you could just declare your constant in your header file, and make it available to anyone including it. Still, that won't have the exact same effect as an external linkage.
// a.h
const int MAX = 3;
// a.cpp
#include "a.h"
int b[a];
An easy solution for constant integers is to use enums:
// g.h
enum { MAX = 3; }
// g.c
#include "g.h"
static char buf[MAX];
You won't be able to take the address of MAX, but in turn you get this at zero memory cost.
extern const int MAX;
int i[MAX];
Can't be done. You could do something like
const int MAX = ReadAnIntegerFromTheConsole();
Perfectly valid and legal, but whoopsies- not a constant expression.
const alone means internal linkage
This is not correct, static indicates internal linkage, const just says the object cannot mutate. Try declaring a variable as
extern static int foo;
Your compiler will complain about conflicting linkage. To share a const between translation units do exactly what you've suggested.
In the header
extern const int MAX;
In the source file
const int MAX = 10; // note you can omit the extern here
Here is a working example that may solve your issue. In summary, define the array size as a constant in a header file. In another header file declare the array as extern. In the example below I reference the array as extern without using an include file for the array.
array_size.hpp
const unsigned int MAX_ARRAY_SIZE = 16;
array.cpp
#include "array_size.hpp"
int array[MAX_ARRAY_SIZE];
main.cpp
#include "array_size.hpp"
// Reference the array from array.cpp
extern int array[MAX_ARRAY_SIZE];
int main(void)
{
array[1] = 7;
return 0;
}
The *array_size.hpp* file defines the size, the identifier can be used in other translation units by including the header.
I compiled on Cygwin using:
g++ -I. -o array.exe main.cpp array.cpp
Why not just use a #define?
#define MAX 3
Related
I have the following three files in my code (with most of the code removed. This is just to isolate the issue).
global.h:
//global.h
#ifndef GLOBAL_H
#define GLOBAL_H
extern const int ARRAYSIZEX;
extern const int ARRAYSIZEY;
extern const int ARRAYSIZEZ;
#endif //GLOBAL_H
global.cpp:
//global.cpp
#include "global.h"
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
main:
//main
#include "global.h"
using namespace std;
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
int main(int argc, char **argv)
{
//...
}
Compiling gives me three errors at the declaration of mySomeTypeArray.
error: array bound is not an integer constant before ']' token
I want to keep my global variable and array size definitions in global.h/cpp for this application, just for organization, so that all my configuration parameters are in one place. What's the proper way to achieve what I'm trying to do?
Thanks
Your declaration is failing because array sizes need to be evaluated at compile-time and your encapsulation scheme is actually hiding the values from the compiler. This is true because compilers work on individual translation units. While compiling main.cpp your compiler sees only extern const int ARRAYSIZEX thanks to the include statement, but not the value which is visible in a separate translation unit so it can't figure out the memory layout.
While const variables can used as array sizes in some contexts, the language provides the more appropriate constexpr qualifier which comes with a set of restrictions that enforce its compile-time evaluation and suitability for array sizes. I recommend always using it when appropriate because it will point you to the error in situations such as this. In this case, you would get a compiler error because an extern constexpr declaration is ill-formed which hints at the proper solution: to hold the values for compile-time constants directly inside the header file.
global.h
constexpr int ARRAYSIZEX = ...;
constexpr int ARRAYSIZEY = ...;
constexpr int ARRAYSIZEZ = ...;
main.cpp
#include "global.h"
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
The problem here is extern int x means "x is defined in another file, but don't worry about the particulars, all you need to know is it's an int". This is normally good enough, except when the compiler needs to know right there and then what x is.
Since that's defined in a whole other file it can't. That file must be compiled before it knows, and the result of that compilation, due to the way C++ works, can't impact the compilation of this file.
You'll need to declare that as a const int in a header if you want to share those values. extern int won't cut it.
Although this is a trivial example, there's really no reason to go down the extern road at all. Just define the values in the header file as regular const int.
Array size must be specified by an integer constant expression. A const int object can be used in an integer constant expression if and only if it declared with an initializer and that initializer is also an integer constant expression. Your ARRAYSIZE... variables do not satisfy that requirement. In main they are declared without an initializer. You cannot use ARRAYSIZE... variables as array sizes in main.
Unless you have a specific requirement to give these variables external linkage, simply declare (and define) them in the header as
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
These object will have internal linkage though, which is different from what your original variant attempts to do.
If really want to give them external linkage, declare them as inline extern const in the header
inline extern const int ARRAYSIZEX = 5;
inline extern const int ARRAYSIZEY = 2;
inline extern const int ARRAYSIZEZ = 4;
Since inline by itself prevents const from imposing internal linkage, extern is entirely optional in these declarations. And since inline const combination can be replaced with constexpr (as #M.M noted in the comments), you can achieve the same effect with just
constexpr int ARRAYSIZEX = 5;
constexpr int ARRAYSIZEY = 2;
constexpr int ARRAYSIZEZ = 4;
The problem here is that ARRAYSIZEX, ARRAYSIZEY and ARRAYSIZEZ are not the compile time constants. They are constants - so their values can't be changed but their values are not known to compiler.
In C++ the compilation process consists of 3 basic steps.
Preprocessing of all source files done by preprocessor.
Compilation for every translation unit (.cpp file) done by compiler. For every translation unit compiler creates an object file.
Linking of all object files done by linker. The output is an executable file.
In C++ the keyword extern for compiler means that the variable is 'somewhere' defined. The compiler doesn't know the variable's real address but by placing keyword extern it's assured that the variable really exists and the linker will be able to find its address by its name when creating the executable file.
The problem here is that compiler in step 2 wants to create the object file but it doesn't known how big the array is going to be because it doesn't know the value of these constants. Yes, linker in step 3 will finally find them when putting together all object files but it's too late for compiler. So it generates that error.
The solution is simple. Use already mentioned constexpr keyword and initialize all variables with initializers. The keyword constexpr marks compile time constants - constants that have to be initialized in initializers and are known to compiler.
I have a problem with an extern variable and an array declaration with it.
How to declare an array with global variable which located not in the declarable file.
file1.cpp
const int size = 10;
mainfile.cpp
extern const int size;
void main()
{
int mas[size];
}
int mas[size];
This line has an issue.
Please any guess??
You can't. An array size must be a constant expression; if it's a variable, then that variable must be const and initialised in the same translation unit, so that its value is available for use as a constant.
If you want to share the value between multiple translation units, define it in a header and include that.
First of all constants have internal linkage. Thus these declarations
file1.cpp
const int size = 10;
and
mainfile.cpp
extern const int size;
refer to different entities.
The constant declared in file1.cpp is not visible outside its corresponding compilation unit.
According to the C++ Standard (3.5 Program and linkage)
3 A name having namespace scope (3.3.6) has internal linkage if it is
the name of
— a non-volatile variable that is explicitly declared const or
constexpr and neither explicitly declared extern nor previously
declared to have external linkage; or
In mainfile the value of size is not specified so the compiler will issue an error for statement
int mas[size];
becuase the size of an array shall be a compile-time constant expression.
The simplest solution is to place the constant definition
const int size = 10;
in some common headet file that will be included in each translation unit where there is a reference to the constant.
int mas[size];
This line has an issue. Please any guess??
As other users pointed, the issue could be that you're trying to create a Variable Lenght Array which is something not allowed in C++ (but almost enter in C++14 as Dynamic Arrays*).
Some compilers accept VLA as an extension (no standard) so I'm guessing that you're using one that doesn't have this extension or have this extension disabled.
Don't worry, you have workarrounds anyway...
#define (don't do that)
Assuming that the issue is the VLA, if we ensure the size as a compile-time value, the problem is solved so...
// file1.hpp <-- This is now a HEADER not a CPP
#define SIZE 10
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[SIZE]; // accepted, equivalent to int mas[10].
}
constexpr
C++11 introduced the constexpr* keyword which can be used to achieve your goal
// file1.hpp <-- This is now a HEADER not a CPP
constexpr int size() { return 10; }
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[size()];
}
enum
Enumerations are compile-time constants, so you can use them this way:
// file1.hpp <-- This is now a HEADER not a CPP
enum constant { size = 10 };
// mainfile.cpp
#include "file1.hpp"
void main()
{
int mas[constant::size];
}
*If someone found a better link, please let me know.
C++ does not allow the size of arrays to be specified at runtime. In your example of course it is specified at link time, but that is no help to the compiler.
If you are using a C++14 compiler however, and on certain other compilers (such as gcc) you can do this, but it is less portable than allocating the memory dynamically, and lest convenient than a std::vector<>.
For reference: https://isocpp.org/wiki/faq/freestore-mgmt#dynamic-array-len
My project consists of only two source files:
a.cpp:
const int n = 8;
b.cpp:
extern const int n;
int main()
{
// error LNK2001: unresolved external symbol "int const n" (?n##3HB)
int m = n;
}
I know there are several methods to make it work; however, I just wonder WHY it does't work?
It's because const implies internal linkage by default, so
your "definition" isn't visible outside of the translation unit
where it appears.
In this case, by far the best solution is to put the declaration
(extern int const n;) in a header file, and include that in
both a.cpp and b.cpp. The linkage is determined by the
first declaration the compiler sees, so the later definition in
a.cpp will have the correct (external) linkage.
Alternatively, you can force the linkage in the definition:
extern int const n = 8;
Despite the extern, this is still a definition; anything with
an initializer outside of a class definition is a definition.
const and constexpr variables in C++ have internal linkage (and thus aren't accessible in other compilation unit) if they aren't also declared extern (either in the definition or in a previous declaration).
In C, it isn't the case (well C hasn't constexpr) so your code is valid, and more you can put extern on a definition.
So if you want to write code which is both C and C++ (and the two declarations should probably come from the same header as James pointed out):
// a.cpp
extern const int n;
const int n = 8;
// b.cpp
extern const int n;
int main()
{
int m = n;
}
if you don't
// a.cpp
extern const int n = 8;
is also possible
Declare it extern in a.cpp and just use without extern in b.cpp:
a.h
extern const int n ;
a.cpp
#include "a.h"
...
const int n= 8
b.cpp:
#include "a.h"
...
int main()
{
int m = n;
}
To share a const object among multiple files, you must define the variable as extern.
To define a single instance of a const variable, we use the keyword extern on both its definition and declaration(s):
From these rules you just need to add the extern keyword in your definition. you already have it in declaration.
If the other answers here do not do the trick, it may be the case that you have your definitions in different namespaces... if the compilation passes, and you get an undefined symbol linker error:
check the namespace of the undefined symbol; that's the effective namespace for the extern const int n declaration.
ensure that's your effective namespace where you make the const int n = 8 definition.
My project consists of only two source files:
a.cpp:
const int n = 8;
b.cpp:
extern const int n;
int main()
{
// error LNK2001: unresolved external symbol "int const n" (?n##3HB)
int m = n;
}
I know there are several methods to make it work; however, I just wonder WHY it does't work?
It's because const implies internal linkage by default, so
your "definition" isn't visible outside of the translation unit
where it appears.
In this case, by far the best solution is to put the declaration
(extern int const n;) in a header file, and include that in
both a.cpp and b.cpp. The linkage is determined by the
first declaration the compiler sees, so the later definition in
a.cpp will have the correct (external) linkage.
Alternatively, you can force the linkage in the definition:
extern int const n = 8;
Despite the extern, this is still a definition; anything with
an initializer outside of a class definition is a definition.
const and constexpr variables in C++ have internal linkage (and thus aren't accessible in other compilation unit) if they aren't also declared extern (either in the definition or in a previous declaration).
In C, it isn't the case (well C hasn't constexpr) so your code is valid, and more you can put extern on a definition.
So if you want to write code which is both C and C++ (and the two declarations should probably come from the same header as James pointed out):
// a.cpp
extern const int n;
const int n = 8;
// b.cpp
extern const int n;
int main()
{
int m = n;
}
if you don't
// a.cpp
extern const int n = 8;
is also possible
Declare it extern in a.cpp and just use without extern in b.cpp:
a.h
extern const int n ;
a.cpp
#include "a.h"
...
const int n= 8
b.cpp:
#include "a.h"
...
int main()
{
int m = n;
}
To share a const object among multiple files, you must define the variable as extern.
To define a single instance of a const variable, we use the keyword extern on both its definition and declaration(s):
From these rules you just need to add the extern keyword in your definition. you already have it in declaration.
If the other answers here do not do the trick, it may be the case that you have your definitions in different namespaces... if the compilation passes, and you get an undefined symbol linker error:
check the namespace of the undefined symbol; that's the effective namespace for the extern const int n declaration.
ensure that's your effective namespace where you make the const int n = 8 definition.
This variable is defined in xyz.cpp
const int i = 10;
The below main() method is written in abc.cpp
void main()
{
cout<<i; //trying to access 'i' from a different .cpp file
}
You need to declare it extern in abc.cpp:
extern const int i;
EDIT: As stated in the comment below, in C++ (unlike C), to give a const variable external linkage, you need to declare it es extern also in xyz.cpp:
extern const int i = 10;
Reference: MSDN
The simplest way is to declare it in a header as const static int i=10; and include that header in all the .cpp that need that constant. This will allow it to be "inlined" by the compiler in every object file, still avoiding ODR violations.
---edit---
Actually, in C++ the static is not required, since const objects have internal linkage by default. But in C, you have to put that static (and in C++ it doesn't hurt).
Why is this better than the extern method? Because:
it's more idiomatic. In C++ you'll always write integral constants in headers as const variables (and that's the very reason why they have internal linkage by default).
it's less typing. You just have to write the const declaration once, then your constants are just a #include away.
it (usually) produces more efficient code. The definition of extern-declared variables cannot be accessed by the compiler when it is producing the current object module, so it cannot optimize it by putting its actual value as an immediate value in the produced machine code, it cannot eliminate branches that cannot be reached with that value of the constant, ... Sure, cross-module optimization ("link time code generation", "whole program optimization", ...) does exist, but at the moment compilers have more advanced optimizers than linkers.
Add the keyword extern in front of it.
Declare it in abc.cpp as:
extern const int i = 10;
const variables in C++ have an internal linkage in C++(unlike C). So to be able to use it in another file you have to explicitly declare it as having external linkage.
Put this global variable into header and #include this header in all .cpp files where you want to use it.
xyz.h:
const int i = 10;
xyz.cpp:
#include "xyz.h"
void main()
{
cout << i;
}
Or if you want to avoid using header for this purpose, you can declare it as extern const int i = 10; in xyz.cpp, but then you have to declare this variable in abc.cpp too, so you should write extern const int i; at the beginning of abc.cpp in order to use it.
The same way as using extern variables.
In the file xyz.cpp:
extern const int i = 333;
In the file abc.cpp:
extern const int i;
cout << i;