static const vs #define
Personally, I loathe the preprocessor, so I'd always go with const
.
The main advantage to a #define
is that it requires no memory to store in your program, as it is really just replacing some text with a literal value. It also has the advantage that it has no type, so it can be used for any integer value without generating warnings.
Advantages of "const
"s are that they can be scoped, and they can be used in situations where a pointer to an object needs to be passed.
I don't know exactly what you are getting at with the "static
" part though. If you are declaring globally, I'd put it in an anonymous namespace instead of using static
. For example
namespace {
unsigned const seconds_per_minute = 60;
};
int main (int argc; char *argv[]) {
...
}
static const vs #define vs enum
It depends on what you need the value for. You (and everyone else so far) omitted the third alternative:
static const int var = 5;
#define var 5
enum { var = 5 };
Ignoring issues about the choice of name, then:
- If you need to pass a pointer around, you must use (1).
- Since (2) is apparently an option, you don't need to pass pointers around.
- Both (1) and (3) have a symbol in the debugger's symbol table - that makes debugging easier. It is more likely that (2) will not have a symbol, leaving you wondering what it is.
- (1) cannot be used as a dimension for arrays at global scope; both (2) and (3) can.
- (1) cannot be used as a dimension for static arrays at function scope; both (2) and (3) can.
- Under C99, all of these can be used for local arrays. Technically, using (1) would imply the use of a VLA (variable-length array), though the dimension referenced by 'var' would of course be fixed at size 5.
- (1) cannot be used in places like switch statements; both (2) and (3) can.
- (1) cannot be used to initialize static variables; both (2) and (3) can.
- (2) can change code that you didn't want changed because it is used by the preprocessor; both (1) and (3) will not have unexpected side-effects like that.
- You can detect whether (2) has been set in the preprocessor; neither (1) nor (3) allows that.
So, in most contexts, prefer the 'enum' over the alternatives. Otherwise, the first and last bullet points are likely to be the controlling factors — and you have to think harder if you need to satisfy both at once.
If you were asking about C++, then you'd use option (1) — the static const — every time.
Static const vs #define for efficiency in C
Consider the following 2 test files
Test1.c: Uses static const foo.
// Test1.c uses static const..
#include <stdio.h>
static const foo = 6;
int main() {
printf("%d", foo);
return 0;
}
Test2.c: uses macro.
// Test2.c uses macro..
#include <stdio.h>
#define foo 6
int main() {
printf("%d", foo);
return 0;
}
and the corresponding assembly equivalences when using gcc -O0
(default) are follows,
Assembly for Test1.c:
0000000000000000 <main>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: 48 83 ec 20 sub rsp,0x20
8: e8 00 00 00 00 call d <main+0xd>
d: b8 06 00 00 00 mov eax,0x6
12: 89 c2 mov edx,eax
14: 48 8d 0d 04 00 00 00 lea rcx,[rip+0x4] # 1f <main+0x1f>
1b: e8 00 00 00 00 call 20 <main+0x20>
20: b8 00 00 00 00 mov eax,0x0
25: 48 83 c4 20 add rsp,0x20
29: 5d pop rbp
2a: c3 ret
2b: 90 nop
Assembly for Test2.c:
0000000000000000 <main>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: 48 83 ec 20 sub rsp,0x20
8: e8 00 00 00 00 call d <main+0xd>
d: ba 06 00 00 00 mov edx,0x6
12: 48 8d 0d 00 00 00 00 lea rcx,[rip+0x0] # 19 <main+0x19>
19: e8 00 00 00 00 call 1e <main+0x1e>
1e: b8 00 00 00 00 mov eax,0x0
23: 48 83 c4 20 add rsp,0x20
27: 5d pop rbp
28: c3 ret
29: 90 nop
In both the cases, it is not using external memory. But the difference is that, #define
replaces foo
by the value, static const
is an instruction so it increments the instruction pointer to the next instruction and it uses 1 additional register to store the value.
By this, we can say that macro is better than static constants but the difference is minimum.
EDIT: When using -O3
compilation option (i.e at optimization on) both the test1.c and test2.c evaluates the same.
0000000000000000 <main>:
0: 48 83 ec 28 sub rsp,0x28
4: e8 00 00 00 00 call 9 <main+0x9>
9: 48 8d 0d 00 00 00 00 lea rcx,[rip+0x0] # 10 <main+0x10>
10: ba 06 00 00 00 mov edx,0x6
15: e8 00 00 00 00 call 1a <main+0x1a>
1a: 31 c0 xor eax,eax
1c: 48 83 c4 28 add rsp,0x28
20: c3 ret
21: 90 nop
So, gcc
treats both static const
and #define
as the same when it optimize.
static const vs. #define in c++ - differences in executable size
As seen in the comments, the typesafe operator| overloading for my enums seems to prevent VC++ from inlining the ORed value. I guess I'll keep using the #define
version as I hate increasing the executable size if there's no benefits (no, this is not premature optimization) - after all, it doesn't increase readability, and since the combination of flags is already of my flagset enum type, I also don't lose any type-safety, I guess.
What is the difference between static const and const?
The difference is the linkage.
// At file scope
static const int a=5; // internal linkage
const int i=5; // external linkage
If the i
object is not used outside the translation unit where it is defined, you should declare it with the static
specifier.
This enables the compiler to (potentially) perform further optimizations and informs the reader that the object is not used outside its translation unit.
Difference between static const and #define in Objective-C
#define myInteger 5
is a preprocessor macro. The preprocessor will replace every occurrence of myInteger
with 5
before the compiler is started. It's not a variable, it's just sort of an automatic find-and-replace mechanism.
static const NSInteger myInteger = 5;
This is a "real" variable that is constant (can't be changed after declaration). Static means that it will be a shared variable across multiple calls to that block.
Linux Kernel: Static Const vs #Define
It used to be that you couldn't do:
const size_t buffer_size = 1024;
unsigned char buffer[buffer_size];
in C, since buffer_size
is not a "real" constant. Therefore you often see
#define BUFFER_SIZE 1024
unsigned char buffer[BUFFER_SIZE];
instead.
As of C99, you can do the former, but not in global scope. It won't work outside of a function (not even if made static
). Since much code in the kernel deals with similiar constructs, that might be one reason for using the preprocessor instead.
Note: don't forget about sizeof
, it's a very good tool when it comes to not repeating the size constant all over the place, regardless of how the constant was implemented.
constexpr vs. static const: Which one to prefer?
As long as we are talking about declaring compile-time constants of scalar integer or enum types, there's absolutely no difference between using const
(static const
in class scope) or constexpr
.
Note that compilers are required to support static const int
objects (declared with constant initializers) in constant expressions, meaning that they have no choice but to treat such objects as compile-time constants. Additionally, as long as such objects remain odr-unused, they require no definition, which further demonstrates that they won't be used as run-time values.
Also, rules of constant initialization prevent local static const int
objects from being initialized dynamically, meaning that there's no performance penalty for declaring such objects locally. Moreover, immunity of integral static
objects to ordering problems of static initialization is a very important feature of the language.
constexpr
is an extension and generalization of the concept that was originally implemented in C++ through const
with a constant initializer. For integer types constexpr
does not offer anything extra over what const
already did. constexpr
simply performs an early check of the "constness" of initializer. However, one might say that constexpr
is a feature designed specifically for that purpose so it fits better stylistically.
Related Topics
Why Is There an Injected Class Name
Is There a Simple Way to Convert C++ Enum to String
Does the Size of an Int Depend on the Compiler And/Or Processor
What's the Best Free C++ Profiler For Windows
When I Change a Parameter Inside a Function, Does It Change For the Caller, Too
Initializer Lists and Rhs of Operators
Why Does C++ Not Have Reflection
How Much Is Too Much With C++11 Auto Keyword
Why Isn't It Legal to Convert "Pointer to Pointer to Non-Const" to a "Pointer to Pointer to Const"
Constructor Initialization-List Evaluation Order
What Happens When I Print an Uninitialized Variable in C++
Can Main Function Call Itself in C++
Why Does Rand() Yield the Same Sequence of Numbers on Every Run