Skip to main content
GameDev.net gamedev.net
🔒 Locked

Using const versus #define

Started by NinjaOne Jan 5, 2001 at 3:30 PM 7 replies 1.3k views
Original Post
NinjaOne
NinjaOne
I''m curious to know what are the advantages and disadvantages of using const versus #define to define symbolic constants. From what I can tell the only thing that const variables preserve is type checking and being able to see the const variable names in a symbolic debugger. Is using #define faster? I ask because I notice that John Carmack uses tons of #defines for symbolic constants in Quake 3 Arena. Andre LaMothe also heavily uses #defines in his code vs. const variables. Wes Bigelow wesbigelow@hotmail.com
-Wes
dusik
dusik
Yes, #define''s I think are faster, but here is the difference, as far as I know:

#define VAR 1

this means that whenever you put VAR in your code, it will substitute a 1, which is some offset byte in the executable, and easily accessible.

const int VAR = 1;

This reserves an integer in memory at startup and keeps it there. Therefore, it wastes memory, and may be slower, but you can access the memory directly. So, for example, you''re doing Direct3D and want to make an identity matrix you will use. You just do:

const D3DMATRIX matID = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

And then when you want to set some matrix equal to the identity matrix, you can just do:

memcpy(&mat, &matID, sizeof(matID));

Which is fast and efficient, right? Correct me if I''m wrong. I myself am rather new to C++/D3D

------------------------
CRAZY_DUSIK* pCrazyDuSiK;
pCrazyDuSiK->EatMicroshaft(MS_MUNCH_BILL_GATES | MS_CHEW_BILL_GATES);
------------------------CRAZY_DUSIK* pCrazyDuSiK = new CRAZY_DUSIK;pCrazyDuSiK->EatMicroshaft(MS_MUNCH_BILL_GATES | MS_CHEW_BILL_GATES);pCrazyDuSiK->WebSiteURL = "http://www.geocities.com/dusik2000";
Wilka
Wilka
This has been covered loads of times before (check the search at the top right of the page).
#define is not faster than const, #define is not type safe and it doesn't care about scope. So you should use const for constants and leave #define for header guards. Quake3 is written in C, so const isn't an option. But you're using C++ so you might as well use it properly

Edited by - Wilka on January 5, 2001 5:02:52 PM
Dire.Wolf
Dire.Wolf
I save #defines for macros that inline functions would be inappropriate for. I always use constants for fixed values etc. Not only is it type-safe but it avoids stupid bugs that can crop up when using #defines.

Constants are just as fast as #defines because compilers can optimize generated code by substituting the constant variable with the variables value.

ex.

const int MAX = 50;

if(int i = 0; i < MAX; ++i)
{
}

becomes (after compiling)

if(int i = 0; i < 50; ++i)
{
}

just like a define but with type-safety. BTW constants are great to use in a class'' public interface.

Dire Wolf
direwolf@digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Aldacron
Aldacron
Wilka - const is an option in C. And, if you look at the Q3 code, you''ll find that const is used quite often with function parameters, while defines are used in favor of global consts.

Personally, whether using C or C++, I generally use defines for values that are meant to be indicators, like object states. But, if I have a value that I know will be used primarily in some sort of calculation, like a global PI, I tend to use const.

Life''s a journey, not a destination... - S. Tyler
Kylotan
Kylotan
There are only a few times when a const variable might be slower/use storage. This would include:
-when you take the address of a const variable (ie pass it by reference, or whatever). It is possible that even this can be optimised out by most compilers, but when you ask for an address, it probably has to generate storage for it at that point.
-when you have const data members of a class. Technically it has to instantiate all those members for each class. (To check this: make an empty class, fill it with a few ''const int''s, and check sizeof(thatClass).) Instead, if you need constants within a class, define them as ''static const'' which will share them among the class and allow the compiler to optimise them out to literals.
NinjaOne
NinjaOne
I got a another response at Codeguru's message boards from "thew". He states (with comments in parentheses by me for clarity):

quote:

Yes const has type checking.. const also gives you more versitility with respect to scope..

But really the way I think of the difference is this..

declaring const is like promising you won't change it.... It leaves open the possiblility of some well intentioned person.. even yourself.. casting that baby to a straight variable and
reneging on the promise you once made in good faith (that the variable was indeed constant).

declaring a #define is taking all options (for making a variable not constant) off the tables.. It ain't freaking changing dynamically.. If it is value x one place it will definitely be value x everywhere.. even if you use #undef it will still happen compile time and not dynamically at run time..



That seems like a fairly powerful argument on the side of using #define.

Wes


Edited by - NinjaOne on January 6, 2001 12:25:39 PM
-Wes
Wilka
Wilka
const does make a compile time constants, just like #define, it''s not dynamically allocated. Consider this program:


template<int N>
struct Test
{
enum{size = N};

Test()
{
cout << size << endl;
}

};


int main()
{
const int size = 5;

Test<size> test;

const_cast<int&>(size) = 10;

cout << size << endl;

return 0;
}


If const didn''t make a compile time value, you wouldn''t be able to use as a template parameter or initialise an enum with it. The output of this program is:
5
5

so trying to change the value has no effect, and if you look at assembly listing, you can see that the compiler has inserted ''5'' in the places where ''size'' have been used:

21: Test<size> test;
004017BF lea ecx,[ebp-8]
004017C2 call @ILT+425(Test<5>::Test<5> (004011ae)

25: cout << size << endl;
004017CE push offset @ILT+200(std::endl) (004010cd)
004017D3 push 5
004017D5 mov ecx,offset std::cout (00486840)
NinjaOne
NinjaOne
Thanks to this discussion and threads on other message boards I''ve decided to use const instead of #define for constant types in my code. The restrictions I''ve put on myself are:

1. Never cast a const to a non-const type.
2. Don''t get memory references to const types.

I would still use #define instead of const if I was using straight C, but I can''t really see any benefit to using #define for this purpose in C++ for myself. It has been confirmed by numerous people and the book, "Learning C++: A Hands-On Approach" by Eric Nagler that built-in type values are kept in a table and substituted into the code as literal constants, similar to #define. BUT, if you take to address of a constant object (assuming any kind of object, fundamental type or otherwise) and store this address into a pointer variable, then storage for the constant itself must be reserved.

The benefits for this usage are normal scoping rules, type checking, and being able see these variable names in the debugger, as well as being as speedy as #define. The big argument on the side of using #define is the fact that you can''t cast to a non-const type, but with my restrictions, this problem is solved also.

Great discussion!
Wes
-Wes

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.