Which one is better to use among the below statements in C?
static const int var = 5;
or
#define var 5
or
enum { var = 5 };
Which one is better to use among the below statements in C?
static const int var = 5;
or
#define var 5
or
enum { var = 5 };
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:
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.
enum
is that they're implemented as int
([C99] 6.7.2.2/3). A #define
lets you specify unsigned and long with U
and L
suffixes, and const
lets you give a type. enum
can cause problems with usual type conversions. –
Flavorsome #define
guaranteed to not consume any extra space? –
Garnes enum
nor #define
uses extra space, per se. The value will appear in the object code as part of the instructions rather than being allocated storage in the data segment or in heap or on the stack. You'll have some space allocated for the static const int
, but the compiler might optimize it away if you don't take an address. –
Mephitis enum { size=10 } ; char str[size] = {0};
–
Pray enum
s (and static const
): they can't be changed. a define
can be #undefine
'd where an enum
and static const
are fixed to the value given. –
Morez #define
would be when one wants to embed major and minor software version numbers (since they don't change very often unlike build number) in a header file in their source code. –
Ment const uint32_t var = 0xFFFF0000;
could result in var = 0x0000? What do the C99 and C89 specs say about the size of a constant? –
Clo int
and be sizeof(int)
bytes long. An enum type variable, however, can be any type, including char
, signed int
and unsigned int
. If you use enum constants, it is very tempting to also use enum variables, but because of a stupid design mistake in the C standard (6.7.2.2), these may not have the same type! In cases where the size of the variable matters, enums variables should be avoided, because they aren't type safe. –
Lys static const a = 5; static const b = a; //warning: use of const variable in a constant expression is non-standard in C
–
Crocket constexpr
instead of const
? –
Buckshee constexpr
will yield a syntax error. In C++, you could (and probably should) use constexpr
when appropriate. I'm not sure I could identify succinctly when constexpr
should be used in preference to const
, though. –
Mephitis constexpr
and const
? –
Mephitis -Wenum-conversion
(which may be enabled by default or with -Wall
) will call out when enums are mixed in both assignments and function calls. –
Thetes Generally speaking:
static const
Because it respects scope and is type-safe.
The only caveat I could see: if you want the variable to be possibly defined on the command line. There is still an alternative:
#ifdef VAR // Very bad name, not long enough, too general, etc..
static int const var = VAR;
#else
static int const var = 5; // default value
#endif
Whenever possible, instead of macros / ellipsis, use a type-safe alternative.
If you really NEED to go with a macro (for example, you want __FILE__
or __LINE__
), then you'd better name your macro VERY carefully: in its naming convention Boost recommends all upper-case, beginning by the name of the project (here BOOST_), while perusing the library you will notice this is (generally) followed by the name of the particular area (library) then with a meaningful name.
It generally makes for lengthy names :)
static
whose address is taken should remain; and if the address is taken one could not have used a #define
or enum
(no address)... so I really fail to see what alternative could have been used. If you can do away with "compile time evaluation", you might be looking for extern const
instead. –
Laveralavergne #if
might be preferable over #ifdef
for boolean flags, but in this case it would make it impossible to define var
as 0
from the command line. So in this case, #ifdef
makes more sense, as long as 0
is a legal value for var
. –
Gastrula static constexpr
? Shouldn't it act exactly as static const without overhead? –
Buckshee constexpr
vs const
is about when the value is evaluated. constexpr
guarantees that the value will be evaluated at compile-time (thus no function executed before main
starts), which also guarantees that said value will be available to the optimizer... however note this is a C question, and there is no constexpr
in C. –
Laveralavergne const
on C means read-only, not constant. You can declare a const inside a block, take a pointer to it and modify its value. See this example –
Epideictic gcc -std=c89 -pedantic
yields warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
and with -O2
prints "const really means constant"
so I am afraid that you are just a victim of a permissive compiler. –
Laveralavergne static
is perfectly acceptable in C++. –
Laveralavergne In C, specifically? In C the correct answer is: use #define
(or, if appropriate, enum
)
While it is beneficial to have the scoping and typing properties of a const
object, in reality const
objects in C (as opposed to C++) are not true constants and therefore are usually useless in most practical cases.
So, in C the choice should be determined by how you plan to use your constant. For example, you can't use a const int
object as a case
label (while a macro will work). You can't use a const int
object as a bit-field width (while a macro will work). In C89/90 you can't use a const
object to specify an array size (while a macro will work). Even in C99 you can't use a const
object to specify an array size when you need a non-VLA array.
If this is important for you then it will determine your choice. Most of the time, you'll have no choice but to use #define
in C. And don't forget another alternative, that produces true constants in C - enum
.
In C++ const
objects are true constants, so in C++ it is almost always better to prefer the const
variant (no need for explicit static
in C++ though).
const int
objects in case-labels is illegal in all versions of C language. (Of course, your compiler is free to support it as a non-standard C++-like language extension.) –
Amy const
means read-only. const int r = rand();
is perfectly legal. –
Fasciation constexpr
as compared to const
specially with the stl
containers like array
or bitset
. –
Stabler switch()
statement, not in case
one. I've just got caught on this one too ☺ –
Ailment The difference between static const
and #define
is that the former uses the memory and the later does not use the memory for storage. Secondly, you cannot pass the address of an #define
whereas you can pass the address of a static const
. Actually it is depending on what circumstance we are under, we need to select one among these two. Both are at their best under different circumstances. Please don't assume that one is better than the other... :-)
If that would have been the case, Dennis Ritchie would have kept the best one alone... hahaha... :-)
const
does use memory. GCC (tested with 4.5.3 and a few newer versions) easily optimizes the const int
into a direct literal in your code when using -O3. So if you do low RAM embedded development (e.g. AVR) you can safely use C consts if you use GCC or another compatible compiler. I have not tested it but expect Clang to do the same thing btw. –
Methinks In C #define
is much more popular. You can use those values for declaring array sizes for example:
#define MAXLEN 5
void foo(void) {
int bar[MAXLEN];
}
ANSI C doesn't allow you to use static const
s in this context as far as I know. In C++ you should avoid macros in these cases. You can write
const int maxlen = 5;
void foo() {
int bar[maxlen];
}
and even leave out static
because internal linkage is implied by const
already [in C++ only].
const int MY_CONSTANT = 5;
in one file and access it with extern const int MY_CONSTANT;
in another. I could not find any info in the standard (C99 at least) about const
changing the default behaviour "6.2.2:5 If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external". –
Flavorsome bar
is a VLA (variable length array); the compiler is likely to generate code as if its length were constant. –
Fasciation Another drawback of const
in C is that you can't use the value in initializing another const
.
static int const NUMBER_OF_FINGERS_PER_HAND = 5;
static int const NUMBER_OF_HANDS = 2;
// initializer element is not constant, this does not work.
static int const NUMBER_OF_FINGERS = NUMBER_OF_FINGERS_PER_HAND
* NUMBER_OF_HANDS;
Even this does not work with a const since the compiler does not see it as a constant:
static uint8_t const ARRAY_SIZE = 16;
static int8_t const lookup_table[ARRAY_SIZE] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; // ARRAY_SIZE not a constant!
I'd be happy to use typed const
in these cases, otherwise...
static uint8_t const ARRAY_SIZE = 16;
all of a sudden no longer compiles can be a bit challenging, particularly when the #define ARRAY_SIZE 256
is buried ten layers deep in a tangled web of headers. That all caps name ARRAY_SIZE
is asking for trouble. Reserve ALL_CAPS for macros, and never define a macro that is not in ALL_CAPS form. –
Absorbance --stc=c89
. The second one doesn't, the compiler complains about "variably modified array"... since ARRAY_SIZE is a (read-only) variable, not a constant. –
Flavorsome static
variables can be used to initialize other static
variables. –
Jacintha If you can get away with it, static const
has a lot of advantages. It obeys the normal scope principles, is visible in a debugger, and generally obeys the rules that variables obey.
However, at least in the original C standard, it isn't actually a constant. If you use #define var 5
, you can write int foo[var];
as a declaration, but you can't do that (except as a compiler extension" with static const int var = 5;
. This is not the case in C++, where the static const
version can be used anywhere the #define
version can, and I believe this is also the case with C99.
However, never name a #define
constant with a lowercase name. It will override any possible use of that name until the end of the translation unit. Macro constants should be in what is effectively their own namespace, which is traditionally all capital letters, perhaps with a prefix.
const
in C99 is still not a real constant. You can declare array size with a const
in C99, but only because C99 supports Variable Length Arrays. For this reason, it will only work where VLAs are allowed. For example, even in C99, you still can't use a const
to declare size of a member array in a struct
. –
Amy const int
size as if it were a C++ const or a macro. Whether you want to depend on this deviation of GCC from the standard is of course your choice, I'd personally go with it unless you can really forsee using another compiler than GCC or Clang, the latter has the same feature here (tested with Clang 3.7). –
Methinks It is ALWAYS preferable to use const, instead of #define. That's because const is treated by the compiler and #define by the preprocessor. It is like #define itself is not part of the code (roughly speaking).
Example:
#define PI 3.1416
The symbolic name PI may never be seen by compilers; it may be removed by the preprocessor before the source code even gets to a compiler. As a result, the name PI may not get entered into the symbol table. This can be confusing if you get an error during compilation involving the use of the constant, because the error message may refer to 3.1416, not PI. If PI were defined in a header file you didn’t write, you’d have no idea where that 3.1416 came from.
This problem can also crop up in a symbolic debugger, because, again, the name you’re programming with may not be in the symbol table.
Solution:
const double PI = 3.1416; //or static const...
#define var 5
will cause you trouble if you have things like mystruct.var
.
For example,
struct mystruct {
int var;
};
#define var 5
int main() {
struct mystruct foo;
foo.var = 1;
return 0;
}
The preprocessor will replace it and the code won't compile. For this reason, traditional coding style suggest all constant #define
s uses capital letters to avoid conflict.
I wrote quick test program to demonstrate one difference:
#include <stdio.h>
enum {ENUM_DEFINED=16};
enum {ENUM_DEFINED=32};
#define DEFINED_DEFINED 16
#define DEFINED_DEFINED 32
int main(int argc, char *argv[]) {
printf("%d, %d\n", DEFINED_DEFINED, ENUM_DEFINED);
return(0);
}
This compiles with these errors and warnings:
main.c:6:7: error: redefinition of enumerator 'ENUM_DEFINED'
enum {ENUM_DEFINED=32};
^
main.c:5:7: note: previous definition is here
enum {ENUM_DEFINED=16};
^
main.c:9:9: warning: 'DEFINED_DEFINED' macro redefined [-Wmacro-redefined]
#define DEFINED_DEFINED 32
^
main.c:8:9: note: previous definition is here
#define DEFINED_DEFINED 16
^
Note that enum gives an error when define gives a warning.
Although the question was about integers, it's worth noting that #define and enums are useless if you need a constant structure or string. These are both usually passed to functions as pointers. (With strings it's required; with structures it's much more efficient.)
As for integers, if you're in an embedded environment with very limited memory, you might need to worry about where the constant is stored and how accesses to it are compiled. The compiler might add two consts at run time, but add two #defines at compile time. A #define constant may be converted into one or more MOV [immediate] instructions, which means the constant is effectively stored in program memory. A const constant will usually be stored in a separate section in data memory such as .const or .rodata. In systems with a Harvard architecture, there could be differences in performance and memory usage, although they'd likely be small. They might matter for hard-core optimization of inner loops.
The definition
const int const_value = 5;
does not always define a constant value. Some compilers (for example tcc 0.9.26) just allocate memory identified with the name "const_value". Using the identifier "const_value" you can not modify this memory. But you still could modify the memory using another identifier:
const int const_value = 5;
int *mutable_value = (int*) &const_value;
*mutable_value = 3;
printf("%i", const_value); // The output may be 5 or 3, depending on the compiler.
This means the definition
#define CONST_VALUE 5
is the only way to define a constant value which can not be modified by any means.
#define
can also be modified, by editing the machine code. –
Rattish 5
. But one can't modify #define
because it's a preprocessor macro. It doesn't exist in the binary program. If one wanted to modify all places where CONST_VALUE
was used, one had to do it one by one. –
Pedometer #define CONST 5
, then if (CONST == 5) { do_this(); } else { do_that(); }
, and the compiler eliminates the else
branch. How do you propose to edit the machine code to change CONST
to 6? –
Fasciation #define
isn't bullet-proof. –
Rattish #define
. The only real way to do that is to edit the source code and recompile. –
Fasciation Don't think there's an answer for "which is always best" but, as Matthieu said
static const
is type safe. My biggest pet peeve with #define
, though, is when debugging in Visual Studio you cannot watch the variable. It gives an error that the symbol cannot be found.
Incidentally, an alternative to #define
, which provides proper scoping but behaves like a "real" constant, is "enum". For example:
enum {number_ten = 10};
In many cases, it's useful to define enumerated types and create variables of those types; if that is done, debuggers may be able to display variables according to their enumeration name.
One important caveat with doing that, however: in C++, enumerated types have limited compatibility with integers. For example, by default, one cannot perform arithmetic upon them. I find that to be a curious default behavior for enums; while it would have been nice to have a "strict enum" type, given the desire to have C++ generally compatible with C, I would think the default behavior of an "enum" type should be interchangeable with integers.
int
, so the "enum hack" can't be used with other integer types. (The enumeration type is compatible with some implementation-defined integer type, not necessarily int
, but in this case the type is anonymous so that doesn't matter.) –
Fasciation int
to an enumeration-typed variable (which compilers are allowed to do) and one tries to assign to such a variable a member of its own enumeration. I wish standards committees would add portable ways of declaring integer types with specified semantics. ANY platform, regardless of char
size, should be able to e.g. declare a type which will wrap mod 65536, even if the compiler has to add lots of AND R0,#0xFFFF
or equivalent instructions. –
Loblolly uint16_t
, though of course that's not an enumeration type. It would be nice to let the user specify the integer type used to represent a given enumeration type, but you can achieve much of the same effect with a typedef
for uint16_t
and a series of #define
s for individual values. –
Fasciation 2U < -1L
as true and others as false, and we're now stuck with the fact that a some platforms will implement a comparison between uint32_t
and int32_t
as signed and some as unsigned, but that doesn't mean the Committee couldn't define an upwardly-compatible successor to C that includes types whose semantics would be consistent on all compilers. –
Loblolly enum : unsigned char { DEL = 127 };
. It has also borrowed constexpr
from C++, for example constexpr unsigned char DEL = 127;
–
Whipping enum
s are very similar to C enum
s; an enum
type is compatible with some integer type. C++ adds enum class
, which lets you define an enumerated type that isn't compatible with any integer type. –
Fasciation enum class
was introduced in C++11,but ordinary enums were unchanged. Is it possible you were using a buggy or non-conforming compiler? In any case, your answer is incorrect for current C++ (at least since 1998) and for any C++ compiler anyone is likely to use. –
Fasciation A simple difference:
At pre-processing time, the constant is replaced with its value. So you could not apply the dereference operator to a define, but you can apply the dereference operator to a variable.
As you would suppose, define is faster that static const.
For example, having:
#define mymax 100
you can not do printf("address of constant is %p",&mymax);
.
But having
const int mymax_var=100
you can do printf("address of constant is %p",&mymax_var);
.
To be more clear, the define is replaced by its value at the pre-processing stage, so we do not have any variable stored in the program. We have just the code from the text segment of the program where the define was used.
However, for static const we have a variable that is allocated somewhere. For gcc, static const are allocated in the text segment of the program.
Above, I wanted to tell about the reference operator so replace dereference with reference.
const
qualifier. C does not have symbolica constants other than enum-constants. A const int
is a variable. You also confuse language and specific implementations. There is no requirement where to place the object. And it is not even true for gcc: typically it places const
qualified variables in the .rodata
section. But that depends on the target platform. And you mean the address-of operator &
. –
Suite We looked at the produced assembler code on the MBF16X... Both variants result in the same code for arithmetic operations (ADD Immediate, for example).
So const int
is preferred for the type check while #define
is old style. Maybe it is compiler-specific. So check your produced assembler code.
I am not sure if I am right, but in my opinion calling #define
d value is much faster than calling any other normally declared variable (or const value).
It's because when program is running and it needs to use some normally declared variable, it needs to jump to exact place in memory to get that variable.
In opposite, when it uses #define
d value, the program doesn't need to jump to any allocated memory; it just takes the value. If #define myValue 7
and the program calling myValue
, it behaves exactly the same as when it just calls 7
.
© 2022 - 2024 — McMap. All rights reserved.