71

It's a simple question, but why would someone use #define to define constants?

What's the difference between

#define sum 1 and const int sum = 1;

10
  • 30
    I'm honestly really tempted to say, "because they're n00bs"... +1 good question Commented Jun 8, 2011 at 3:55
  • 2
    Yeah this one should bring out some amusing answers Commented Jun 8, 2011 at 4:02
  • 3
    @user Very simple, if you're programming in C++ -- just follow Scott Meyer's advice Item#1 'Prefer const and inline to #define'. Use '#define' as a last resort where const would not work. For example, header inclusion guards etc. Commented Jun 8, 2011 at 4:05
  • 6
    Here's a tip to reduce the risk of getting many disparate answers: don't ask a question in a title and a different question in the body. They're similar, but have different ways to answer. Commented Jun 8, 2011 at 4:05
  • 1
    @Nemo of course, how else can he rack up some rep points real quick? :P Commented Jun 8, 2011 at 4:08

10 Answers 10

53

#define has many different applications, but your question seems to be about one specific application: defining named constants.

In C++ there's rarely a reason to use #define to define named constants.

#define is normally widely used in C code, since C language is significantly different from C++ when it comes to defining constants. In short, const int objects are not constants in C, which means that in C the primary way to define a true constant is to use #define. (Also, for int constants one can use enums).

Sign up to request clarification or add additional context in comments.

7 Comments

@AndreyT man i am scared here :| , what's the rule is this true answer , cause of points ?
@user788552 more points to an answer doesn't mean it's true always
static const int and enum {...} are real constant constants in C++
@CygnusX1: In C++ there's no need for static in front of const int. In C++ const objects have internal linkage by default.
@BlueRaja - Danny Pflughoeft: Well, just because the language is defined that way. In C language you cannot use const int object as case label, as bitfield size, as array size for non-VLA array specifically because const int objects are not constants in C. The term "constant" in C refers to literal constants (like 25) and to enum members, but not to const objects.
|
47

No one should not!
Actually, One should prefer const int sum = 1; over #define sum 1 for a number of reasons:

Scope Based Mechanism:

#defines don't respect scopes so there is no way to create a class scoped namespace. While const variables can be scoped in classes.


Avoiding Weird magical numbers during compilation errors:

If you are using #define those are replaced by the pre-processor at time of precompilation So if you receive an error during compilation, it will be confusing because the error message wont refer the macro name but the value and it will appear a sudden value, and one would waste lot of time tracking it down in code.


Ease of Debugging:

Also for same reasons mentioned in #2, while debugging #define would provide no help really.


Thus, to avoid the above situations const will be a better choice.

6 Comments

@Martinho, if any of the answer starts with # in SO then it makes everything in big bold.
@Mehrdad, #define X can be virtually scoped using #undef X
@iammilind: Not really. If it's previously defined, it'll lose the previous value -- it's not like push/pop'ing a stack.
lol, "why would someone use #define ?" "for a number of reasons: 1) it sucks 2) it sucks 3) it sucks"
@Martinho Fernandes: ;) lol The Q title seriously needs an edit!
|
7

For the example that you just gave, I would normally use a const. Except of course, the #define can be used for conditional compilation elsewhere:

#if SOME_DEFINE == 1 // Conditional code #endif 

This is something you can't do with a const. If you don't need the value to be accessible from the preprocessor, I'd say use a const unless there's some reason why that's not possible. There's some stuff on this in the C++ FAQ lite, where they rightly point out that just because the preprocessor is "evil", it doesn't mean you'll never need it.

4 Comments

I wouldn't say that constant can't be used for conditional compilation. You can specialize a template for the constant. Take a look here for instance.
Yes, but I can't use that to conditionally #include <windows.h> depending on platform or something like that. So I'd say it can't be used for certain types of conditional compilation. ;)
I would use build system to make such sort of choices rather then defines.
I'm not making any recommendation on how to do conditional compilation, I'm just pointing out one possible thing you can do with #defines that isn't (easily) accomplished with a const.
4

#define is necessary to make things like inclusion guards work, because C++ doesn't have a real module import system.

#define causes a literal textual substitution. The preprocessor understands how to tokenize source code, but doesn't have any idea what any of it actually means. When you write #define sum 1, the preprocessor goes over your code and looks for every instance of the token sum and replaces it with the token 1.

This has a variety of limitations: #define sq(x) x * x will not work right if you use it like sq(3+3); and using #define for a constant does not respect scope in any way, nor does it associate any kind of type with the constant. However, #define can be used (especially in combination with some other special stuff like the # and ## preprocessor operators) to do some magic that is otherwise not possible (except by manually doing what the preprocessor does).

5 Comments

I'd say the first sentence is an answer, and the rest is just things that the OP probably already knew.
I thought that one should use #pragma once instead of inclusion guards in C++.
#pragma once is compiler-specific. The Standard does not define the meaning of pragmas.
But it is widely supported and usually makes #define unnecessary for this purpose.
agree, but most(all?) compilers support it.
2

Always try to use "const int", rather than #define.

Use #define, only when your preprocessor code might be read by another tool, and it's easier for it to go with the preprocessor, rather than to parse the language.

Also it's the only way to define something to be checked later by #if/#else/#endif

Comments

1

From Introduction to programming with C++ which was written by Daniel Liang stated that:

When you define a constant using #define directive, the constant is not stored in memory.The constant will be replaced with a value by compiler. When you declare constant using const keyword, the constant is stored in memory just like variable.

If constant need to be used in multiple programs, use #define to define it in header file so it can be included in other program. If constant used only in one program, using const to declare is more efficient.

Comments

1

Some people have a [misinformed] belief that macros are ensured to be 'real' constants and would be replaced as it is while generating the machine instructions. But modern compilers will ensure that the constant literals are treated the same way.

In simple words

#define sum 1 /*is pre processed*/ 

Which means, that sum doesn't exist after the preprocessing stage is finished.

const int sum = 1; /*is compiled/linked*/ 

Which means sum exists till the executable is made out of your program.

1 Comment

Doesn't answer the OP's question of why one is used over the other. (Don't wanna be harsh, but it really doesn't answer it, sorry.) -1
0

The first is a preprocessor directive, before the compiler compiles your code, it will go through and replace sum with 1. The second declares a variable in memory to hold that quantity. I'm sure it can be argued as to which is best, but the "const int" is probably more common in C++ (when it comes to numeric constants).

http://www.geekpedia.com/KB114_What-is-the-difference-between-sharpdefine-and-const.html

7 Comments

const int does not declare a variable in memory; the linked article is incorrect.
@Don: can't you do const int sum = 1; const int* sum_ptr = &sum;?
Doesn't answer the OP's question of why one is used over the other. (Don't wanna be harsh, but it really doesn't answer it, sorry.) -1
"declare a variable in memory" probably isn't precise enough to be described as true or false, really.
@Martinho Fernandes: C++ Standard 7.1.5.1.3: "A pointer or reference to a cv-qualified type need not actually point or refer to a cv-qualified object, but it is treated as if it does." Casting away const-ness and assigning to such a pointer or reference has undefined behaviour.
|
0

The argument against const variables is already shown in iammilind's answer, compiling/linking performance concerns.

Defining integer constants by #define is a behavior I observe predominantly among older C developers and C++ developers who are actually old-school C developers or are guided by such to work non-invasively on older code bases.

Interestingly, the use of enum for the same purpose is often unknown. Whenever I have the opportunity, I convert groups of related #defines to enumerations. For named constants that do not belong to any group, I use nameless enumerations.

enum { sum = 1 }; 

This way, we get compile-time constants that work in C and C++.

Comments

-1

const int is just an int that can't change. #define is a directive to the C preprocessor, which is much more than just for defining constants.

See here for more details: http://en.wikipedia.org/wiki/C_preprocessor

1 Comment

Doesn't answer the OP's question of why one is used over the other. (Don't wanna be harsh, but it really doesn't answer it, sorry.) -1