Mixing extern and const
- Yes, you can use them together.
- And yes, it should exactly match the declaration in the translation unit it's actually declared in. Unless of course you are participating in the Underhanded C Programming Contest :-)
The usual pattern is:
- file.h:
extern const int a_global_var;
- file.c:
#include "file.h"
const int a_global_var = /* some const expression */;
Edit: Incorporated legends2k's comment. Thanks.
extern const in embedded C programming
Extern const will be loaded from the data section of the compiled binary, which is stored on hard disk, into memory. During execution, it is always in memory. To be precisely, it will be in the data section of the process.
Question about variables with combination of extern and const
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];
Mixing declarations with extern, static and no storage specifier in global scope
If you define an identifier without the keyword static
, it's published in the object file and can be accessed by other modules. So if you again define that identifier without static
in another module, you'll get a conflict: two published identifiers.
If you use the keyword
static
, then (most of) the rest of this doesn't apply.
The problem is the difference between declaring the identifier and defining it. The first says "there's going to be an identifier X
with this type". The second says "here's something that I'm going to call X
of this type".
With functions it's easy: don't provide the body, and it's merely a declaration. Provide the body, and it's a definition too. You can use
extern
to make this explicit in a header file but since it's the default, that's not usual.With variables it's harder. Simply declaring the variable defines it too - thus you can initialise it while defining it. If you want to only declare it, you need to use the keyword
extern
- but then you can't initialise it too. You're saying "there's going to be a variable calledX
" - so you can't have the temerity of deciding its definition too!
That's why in header files all variables should be explicitly declared either extern
or static
:
- The first is usual: there will be a common variable that everyone can access. Don't forget that somewhere, in one module, you need to provide the actual definition, without the
extern
keyword, with an optional initialisation value. - The second is rare: each module that includes the header file will have its own, non-conflicting variable with that particular name. The compiler may be able to not allocate memory for it (especially if it's a constant) - but if it does allocate memory, it'll be different in every module. Why would you do this? Maybe the (forced) inline functions of that header file need each module to have their own copy...
Mixing functions and const/let inside conditional statements cause ReferenceError in Safari
Function declarations inside blocks weren't defined in the specification for many years but they were allowed by different javascript engines.
Since this syntax was not defined in the specification and was allowed by the javascript engines, different engines did different things. Some made it a syntax error, others treated function declarations in block scopes as they were function expressions. Some engines treated functions declarations in a block scope like multiple hoisted declarations in the same scope.
As of ES2015, function declarations are part of the specification and there are two ways they are handled:
- Standard web semantics
- Legacy web semantics
Standard Semantics
With standard semantics, function declarations are converted to function expressions, declared with let
keyword and are hoisted at the top of the block. Standard semantics are in effect in strict mode.
So in strict mode, your code will be treated by the javascript engine as though it were written like this:
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
myFunc();
}
Legacy Web Semantics
In non-strict mode on browsers, legacy web semantics apply. When function declarations in block scope are not treated as syntax errors, there are three scenarios that are handled the same way by all major javascript engines. Those three scenarios are:
- Function is declared and referenced within a single block
- A function is declared and possibly used within a single Block but also referenced by an inner function definition that is not contained within that same Block.
- A function is declared and possibly used within a single block but also referenced within
subsequent blocks.
In addition to let
variable for the function defined in block scope, there's also a variable defined with var
in the containing function scope or the global scope. This var
assignment isn't hoisted to the top of the block and is done when the function declaration is reached in the code.
Your code in non-strict mode is treated by javascript engine as:
var varMyFunc;
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
varMyFunc = myFunc; // at the place of function declaration
myFunc();
}
You shouldn't write code that relies on legacy web semantics. Instead, use strict mode to ensure that your code relies on standard rules for handling function declarations in block scopes. Having said all that, if you have legacy code in non-strict mode that relies on legacy web semantics, you can expect it to work cross-browser.
Will replacing 'extern const' with 'static const' affect performance?
A static const
variable will be a compile-time constant unless volatile
or initialized by a function.
(with any decent optimizing compiler, anyway)
So if you do go with static const
variables, you could get a speed increase and a smaller binary.
An example would be:
extern volatile const int n;
int main(){
volatile int i = n;
}
volatile const int n = 5;
Which has the x86 assembly:
main:
mov eax, DWORD PTR n[rip]
mov DWORD PTR [rsp-4], eax
xor eax, eax
ret
n:
.long 5
we have to use volatile
to force the compiler to take the variable's address (that would happen if the variable weren't volatile
but were in another translation unit) and not optimize out the int i
.
That same example with static const
:
static const int n = 5;
int main(){
volatile int i = n;
}
has the x86 assembly:
main:
mov DWORD PTR [rsp-4], 5
xor eax, eax
ret
We don't have to use volatile
on the constant because we would be exposing the variable exactly the same way as if we were using a header, but we still need to stop the compiler optimizing out i
.
You can see that the static const
way has one less instruction and that the extern
way has extra data added to the binary for the literal that needs to be stored for reference.
So we get better performance and a smaller binary. Although, I admit, these examples are pretty trivial.
This is actually still not a perfect representation, either. If we had const int n
defined in another translation unit, without link-time optimizations, the compiler wouldn't be able to output n: .long 5
and would have to reference another variable. But we'll give the example the benefit of the doubt.
These optimizations are extremely common and you can essentially rely on it being available.
The only thing to watch out for is if you write something like this:
static const int n = some_func();
int main(){
volatile int i = n;
}
the compiler won't be able to substitute n
for its literal value. This would add bloat to your binary because you're defining it in a header and it will be re-declared once in every translation unit. So extern
would be better for space in that case, maybe not in speed though; you can test that yourself. Just mix and match if you really need to micro-optimize.
[all of the examples were compiled with gcc 4.9.2 from https://gcc.godbolt.org/ and used the flag -O3]
C++ How to share constants with extern between cpp - Error: storage class specified
Firstly, these don't seem to be class members. The way you're using extern
it looks like you intended for these to be free. Perhaps in a namespace. Take them out of that class.
Then, when you define them, leave out the extern
.
In this context it means "find this variable elsewhere". You don't want to find it elsewhere. It's here!
// Header
namespace Constants {
extern const std::string DELIMITER;
extern const std::string FILENAME;
extern const int BLUCAR;
extern const int REDCAR;
extern const int EMPTY;
extern const int SPARSE_LIM;
}
// Source
namespace Constants {
const std::string DELIMITER = ",";
const std::string FILENAME = "cars.csv";
const int BLUCAR = 1;
const int REDCAR = 2;
const int EMPTY = 0;
const int SPARSE_LIM = 5;
}
Remember, you'd do the same for static
object definitions!
Related Topics
Generating One Class Member Per Variadic Template Argument
How to Initialize Static Members in the Header
How to Use Signal Inside a C++ Class
Is 'Bool' a Basic Datatype in C++
Gsl::Not_Null<T*> VS. Std::Reference_Wrapper<T> VS. T&
The Difference Between Delete and Delete[] in C++
How to Use New Std::Byte Type in Places Where Old-Style Unsigned Char Is Needed
Why "Universal References" Have the Same Syntax as Rvalue References
Using a Static Library in Qt Creator
Compile Lua Code, Store Bytecode Then Load and Execute It
How to Format Date Time Object with Format Dd/Mm/Yyyy
Purpose of a ".F" Appended to a Number
Differencebetween a .Cpp File and a .H File
What Is Activation Record in the Context of C and C++
What's an Expression and Expression Statement in C++