extern variable and array declare issue c++ - c++

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

Related

c++ extern constant int for array size

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.

C++ Referencing extern const within a namespace

I am trying to use the constant int SIZE that is declared in the TaxConstants.hpp namespace TAXCONSTANTS in other places in my project. When I try to compile, I get "undefined reference to 'SIZE' everywhere that SIZE is referenced.
file TaxConstants.hpp
#ifndef TaxConstants_hpp
#define TaxConstants_hpp
namespace TAXCONSTANTS
{
extern const int SIZE = 4; // I have tried with and without extern
}
#endif //TAXCONSTANTS_HPP
main.cpp
#include <iostream>
#include "TaxConstants.hpp"
using namespace std;
using namespace TAXCONSTANTS;
int main()
{
extern const int SIZE;
// This is a struct defined in another file. It is a sample of my use for SIZE. I left out the #include above to simplify things.
taxPayer payers[SIZE];
//More code
return 0;
}
Additional info: this is a school project and my teach has made it a requirement to declare constants in the file TaxConstants.hpp in the namespace TAXCONSTANTS.
There are 5 files in total, the file with my functions is having the same undefined reference to SIZE error.
I have spent hours looking up similar explanations on the extern function and namespaces, but most of the suggestions are against doing this in the first place an offer another solution. I, unfortunately can not use them. Other errors people had were getting "multiple decorations" which I am not having.
EDIT
See Brians explanation below for better detail.
What I needed to do was define
const int SIZE = 4;
within the TaxConstants.hpp file in namespace TAXCONSTANTS.
Then remove
'extern const int SIZE;'
from my main file and instead reference SIZE by TAXCONSTANTS::SIZE everywhere I wanted to use size.
This is basic namespace stuff that I completely forgot about.
If you define SIZE without the extern keyword, it will have internal linkage since it is const. You can refer to it inmain.cpp as TAXCONSTANTS::SIZE. This is recommended since the compiler will be able to inline the value wherever SIZE is used.
If you define SIZE with the extern keyword, it will have external linkage and it should not be in a header, unless you want multiple definition errors. You should instead define it in a .cpp file which will be linked into the rest of the program. In this case there will be only one copy of SIZE in the entire program. You should avoid this approach (preferring instead the approach without extern) unless for some reason you actually need to have only one copy of SIZE in the entire program.
In both cases, SIZE will be a member of the TAXCONSTANTS namespace.
Your attempt to redeclare SIZE inside main does not do what you think it does! The following inside main:
extern const int SIZE;
actually has the effect of declaring SIZE in the global namespace. Since there is no definition of SIZE in the global namespace, you get undefined reference errors at link time. It is not the correct way to refer to the SIZE variable defined in TAXCONSTANTS.
Multiple problems with the entire approach.
Your
extern const int SIZE;
in main is a declaration of const int object SIZE from global namespace - ::SIZE. This SIZE has absolutely nothing to do with your TAXCONSTANTS::SIZE. Such global ::SIZE object is not defined in your program, which is why you get "undefined reference" error.
Since you already declared TAXCONSTANTS::SIZE in the header file, you don't need to redeclare SIZE again in main. Why are you doing this?
Just remove the declaration from main and use SIZE from TAXCONSTANTS either through using namespace TAXCONSTANTS or by specifying a qualified name TAXCONSTANTS::SIZE.
The declaration you have in the header file is actually a definition. Including this header file into multiple translation units will result in another error: multiple definitions of the same object with external linkage.
If you want to declare a global constant object, you have to keep a mere non-defining declaration in the header file
namespace TAXCONSTANTS
{
extern const int SIZE; // declaration, not definition
}
and move the definition into one of implementation files
namespace TAXCONSTANTS
{
extern const int SIZE = 4; // definition
}
However, it appears that you are planning to use this constant as an Integral Constant Expression (as array size in array declaration). An extern const int constant declared without an initializer will not work for that purpose.
Just forget about extern and declare a normal constant with internal linkage in the header file
namespace TAXCONSTANTS
{
const int SIZE = 4; // definition with internal linkage
}
and then just use in everywhere it is needed
using namespace TAXCONSTANTS;
int main()
{
taxPayer payers[SIZE];
...
}
or
// no 'using namespace TAXCONSTANTS;'
int main()
{
taxPayer payers[TAXCONSTANTS::SIZE];
...
}

Static Global Variable Not Shared Between Threads [duplicate]

I know that this program is not using the static variable in an appropriate way, but it shows how to reproduce a behavior I have seen :
Main.cpp :
int main(){
MyObject* p = new MyObject();
Header::i = 5;
printf("i %i\n", Header::i);
p->update();
return 0;
}
MyObject.cpp :
MyObject::MyObject(){
}
void MyObject::update(){
printf("i %i\n", Header::i);
}
Extern.h :
namespace Header {
static int i;
};
The output I get is :
i : 5
i : 0
Why don't I get 5 for both outputs ? Where does this 0come from ?
Could you explain how static variables work ?
Static variables have internal linkage which effectively means they are local to the compilation unit. Since you have the static variable declared in a header included in 2 source files, you basically have 2 distinct variables: one i local to MyObject.cpp and another, different i, local to main.cpp
You have one static variable per translation unit where you include the header, because static variables have internal linkage.
Where does this 0 come from ?
You've not initialized the variable in the second translation unit, and static variables are zero-initialized, that's where the 0 comes from.
In the standard (§3.6.2/2):
Variables with static storage duration (3.7.1) [...] shall be zero-initialized (8.5) before any other initialization takes place.[...]
You have two variables i
static int i;
because it has internal linkage. That means that each compilation unit where the corresponding header was included has its own object i and other compilation units know nothing about presnece of that object in this compilation unit.
If you will remove specifier static then the linker should issue a message that the variable is defined twice.
The same effect can be achieved if to place a variable in an unnamed namespace in C++ 2011. For example instead of
namespace Header {
static int i;
};
you could write
namespace {
int i;
};
In this case varaible i also has internal linkage. This is valid for C++ 2011.
You should not put static valiables in header files. That leads to every cpp file that includes that header to have a copy of that static local to its compilation unit.
What you could do is extern storage specifier:
Header:
namespace Header {
extern int i;
}
Cpp:
namespace Header {
int i = 0;
}
As an addition to the all the answers. WHY it happens, was already explained. However HOW to fix it, was suggested till now only by using static/extern approach. This is little bit C-like. Unles you don't have to use the header in C-part of the project with C-linkage, you could use C++.
So IF you have really to use something static in your code.
Either declare the variable as a member of a class:
header.h
MyGlobalVariableHoler
{
public: static int i;
};
main.cpp
// class' statics have has to be initialized, otherwise linker error.
int MyGlobalVariableHoler::i=0;
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::i=4711;
Or use a singleton to avoid the explicit initialization
header.h
MyGlobalVariableHolder
{
MyGlobalVariableHolder(){i=0;}
public:
static MyGlobalVariableHolder & instance()
{
static MyGlobalVariableHolder inst;
return inst;
}
int i;
};
any_code.cpp
#include <header.h>
MyGlobalVariableHolder::instance().i=4711;
Its better to declare your variable with extern in your header file to specify that it has an external linkage. Otherwise the above behavior will occur or potential compile or link problems can happen.
static int i ; // i has internal linkage
extern int i ; // i has external linkage
You are getting confused with class level static variable with namespace level static variable. Both are accessed by X::y qualification, adding to confusion. Others have explained actual reason (at the compilation/linkage level).
The variable that is declared static only has scope in the file in which it is declared where as the variable declared without static can be accessed from other files using an extern declaration.

How to access global const variable present in one file to different file

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;

Question about variables with combination of extern and const

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