Jump to content

  • Log In with Google      Sign In   
  • Create Account

Global variables in comparison to #define


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
28 replies to this topic

#1 littletray26   Members   -  Reputation: 267

Like
2Likes
Like

Posted 05 July 2012 - 04:50 PM

As far as I can understand, if you use the pre processor command #define, for example, #define money 100, it'll replace all the instances of "money" and replace them with 100. As far as I know it is global and can be used all over your code?

What is the point of using #define instead of a global variable? Don't they pretty much do the same thing?
What's the difference between the two?
The majority of Internet Explorer users don't understand the concept of a browsing application, or that there are options.
They just see the big blue 'e' and think "Internet". The thought process usually does not get much deeper than that.

Worms are the weirdest and nicest creatures, and will one day prove themselves to the world.

I love the word Clicky :)

Sponsor:

#2 Aardvajk   Crossbones+   -  Reputation: 5981

Like
5Likes
Like

Posted 05 July 2012 - 04:58 PM

Global variables respect namespaces. For example:


int x;



struct s

{

    char x;

};



void f(s v)

{

   v.x = 23; // okay

}



#define x 100



void g(s v)

{

   v.x = 34; // gets converted to v.100 by preprocessor, not good

}



This silly example is just that, but try working with an API that makes heavy use of the preprocessor, for example Win32 API, and you soon find the problems.

Another point of course is that the compiler can produce more meaningful error messages with proper variables. And any decent compiler will generate the same code for a const T t as a #define.

There's no reason really to use the preprocessor for anything except including files, conditional compilation and weirdo stuff like __LINE__ and __FILE__ macros these days. Rule of thumb - if it is possible to do it without the preprocessor, do it the other way.

#3 ApochPiQ   Moderators   -  Reputation: 15698

Like
9Likes
Like

Posted 05 July 2012 - 04:59 PM

A #define macro is more akin to a global constant than a global variable. For instance, this code won't compile:

#define MONEY 100
int main () {
   MONEY = 50;
}

Whereas this is totally legit:

int MONEY = 100;
int main () {
   MONEY = 50;
}


To get similar to a define you want something like this:

const int MONEY = 100;
int main () {
   MONEY = 50;  // oops, won't compile (but is more useful error than the #define version, try it!)
}


#define basically creates a text substitution in your code, like a programmable find and replace. It is handy when you want to do precisely that - replace one bit of text with another. It is dangerous for many reasons, some of which are covered here for example.


In general, you should prefer constants to macros.

#4 Zoomulator   Members   -  Reputation: 273

Like
2Likes
Like

Posted 05 July 2012 - 05:01 PM

I'm assuming you mean C++.

A define statement replaces -any- instance of "money" in your code, no matter if it's a variable or function in any namespace or scope. You get no namespace and the possibility of name clashes is pretty much guaranteed unless you give it a very long and unique name like "MYPROJECT_MONEY". A const global can be overridden in a scope defining another instance of "money" and you can even put it in a specific namespace avoiding other files declaring the same name.

Defines are uncontrollable and will find a way of leaking into places where you don't want it unless you give them very specific and ugly names. The windows.h header is a great example of this.. you better define LEAN_AND_MEAN before using it and hope all the defines really get undefined.

They're only "global" in the sense that if you include a file with it, you'll include the define it contains as well. But the same goes for globally defined const values, so there's no difference there.

#5 littletray26   Members   -  Reputation: 267

Like
0Likes
Like

Posted 05 July 2012 - 05:31 PM

So basically you're all saying that if I can use a global constant rather than a #define, I should?
The majority of Internet Explorer users don't understand the concept of a browsing application, or that there are options.
They just see the big blue 'e' and think "Internet". The thought process usually does not get much deeper than that.

Worms are the weirdest and nicest creatures, and will one day prove themselves to the world.

I love the word Clicky :)

#6 Zoomulator   Members   -  Reputation: 273

Like
1Likes
Like

Posted 05 July 2012 - 05:42 PM

So basically you're all saying that if I can use a global constant rather than a #define, I should?

You can only benefit by doing so. Const values can be defined in headers as well. If you need a global variable (god forbid) you'll have to use the extern keyword in the header and define it in an implementation file.

#7 davepermen   Members   -  Reputation: 1007

Like
1Likes
Like

Posted 06 July 2012 - 04:53 AM

define is just a text replace, and does not care about the language. that can lead to some interesting abuses, and some interesting uses (the header include once thing). other than that, use language features, as they don't want to bite you in the back.

like #define max did all the time for me...

if you don't plan to ctrl-r replace-all-text, don't use #define.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud


#8 krippy2k8   Members   -  Reputation: 646

Like
1Likes
Like

Posted 06 July 2012 - 03:48 PM

Preprocessor macros can be useful for many things, but I would not use them for constant values because you lose type safety and conflicts are possible that could create really hard to find bugs.

#9 L. Spiro   Crossbones+   -  Reputation: 13577

Like
1Likes
Like

Posted 07 July 2012 - 08:40 AM

The above advice is all perfectly valid and I don’t want my post to be misunderstood as a way to “get around” these faulty macro points—there is no real substitution for inlined functions etc.

I just want to add some safety tips for those few times when you really do need a macro.
  • Naming macros such as “MONEY” is too generic. Due to the consequences of text replacement, you could end up with some very abstract and hard-to-trace errors if you use too-general names for your macros. The best way to combat this is to add a fake namespace to your macro. For example, in my engine there are 16 projects each with one namespace. lse, lss, lsm, lsg, etc. Within those projects, I replicate the namespaces within the macros. LSE_ELEMENTS( VAR ), LSG_OPENGL, LSG_DIRECTX11, etc.
  • The above not only reduces conflicts but also lets know you 2 things: #1: Is this macro from my own library?, and #2: Which library? LSG_ = L. Spiro Graphics library. Easy.
  • #undefine macros as soon as they are no longer needed. Header guards etc. should never be undefined, but within translation units (.cpp files) you might have some macros inside functions to make some tasks easier. An example in my engine is “#define LSG_HANDLE2CBUF( HANDLE )”, which, in DirectX 11 and DirectX 10, translates my custom handle into a custom cbuffer pointer, and is used only inside the CDirectX11CompiledShader and CDirectX10CompiledShader .CPP files. It is considered tidy to clean up after yourself, so #undef at the bottom of the .CPP files is a good idea. I have heard rumors of the possibility of macros “leaking” from one translation unit into another under some compilers so this is a good idea in general to avoid bugs.
  • __ (2 underscores) is a prefix reserved for the system/compiler. If you want to make absolutely sure your macros will never conflict with anything, you could add some underscores in front, but make sure it is not just 2 underscores. At work we use 3.


L. Spiro

Edited by L. Spiro, 07 July 2012 - 08:40 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#10 sundersoft   Members   -  Reputation: 216

Like
0Likes
Like

Posted 07 July 2012 - 03:18 PM

__ (2 underscores) is a prefix reserved for the system/compiler. If you want to make absolutely sure your macros will never conflict with anything, you could add some underscores in front, but make sure it is not just 2 underscores. At work we use 3.


Anything starting with two underscores or one underscore and a capital letter is reserved for the compiler. So, anything starting with three underscores is reserved (since it also starts with two underscores) and any capitalized macro that starts with any underscores is reserved. Also, there can't be any sequence of two underscores in the identifier, even if it's not at the start. The compiler is not likely to define a macro that starts with three underscores but it is still allowed to do so.

#11 Cornstalks   Crossbones+   -  Reputation: 6989

Like
1Likes
Like

Posted 07 July 2012 - 06:29 PM

so #undef at the bottom of the .CPP files is a good idea.

I agree with most of #3 except for doing this, as I think it's going too far. I think if I saw it being done I'd say "WTF are they doing this for???" (and I think 99.99% of other programmers would say the same (what I'm trying to say is you'll just confuse other programmers for the most part with it)). I've never heard of a compiler needing this, and I think following it just on "rumor" is going waaay too far, asking for unnecessary mental overhead in developing. Additionally, if a compiler leaks macros/identifiers it shouldn't from one translation unit to another, it's worth reporting that bug to the compiler vendor, and expecting them to fix it.


__ (2 underscores) is a prefix reserved for the system/compiler. If you want to make absolutely sure your macros will never conflict with anything, you could add some underscores in front, but make sure it is not just 2 underscores. At work we use 3.


Anything starting with two underscores or one underscore and a capital letter is reserved for the compiler. So, anything starting with three underscores is reserved (since it also starts with two underscores) and any capitalized macro that starts with any underscores is reserved. Also, there can't be any sequence of two underscores in the identifier, even if it's not at the start. The compiler is not likely to define a macro that starts with three underscores but it is still allowed to do so.

+1. In addition: "Each name that begins with an underscore is reserved to the implementation for use as a name in the
global namespace." So macros simply should never start with an underscore, and no variable in the global namespace should either, even if it's followed by a lower case letter.

Edited by Cornstalks, 07 July 2012 - 06:32 PM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#12 ApochPiQ   Moderators   -  Reputation: 15698

Like
0Likes
Like

Posted 07 July 2012 - 08:44 PM


so #undef at the bottom of the .CPP files is a good idea.

I agree with most of #3 except for doing this, as I think it's going too far. I think if I saw it being done I'd say "WTF are they doing this for???" (and I think 99.99% of other programmers would say the same (what I'm trying to say is you'll just confuse other programmers for the most part with it)). I've never heard of a compiler needing this, and I think following it just on "rumor" is going waaay too far, asking for unnecessary mental overhead in developing. Additionally, if a compiler leaks macros/identifiers it shouldn't from one translation unit to another, it's worth reporting that bug to the compiler vendor, and expecting them to fix it.



Actually, #undefing your macros is still a good idea, in case someone gets antsy about build times and tries to deploy a unity build structure to your C/C++ project. Leaving macros defined all over the place can get incredibly painful in unity builds.

#13 Cornstalks   Crossbones+   -  Reputation: 6989

Like
0Likes
Like

Posted 07 July 2012 - 08:57 PM



so #undef at the bottom of the .CPP files is a good idea.

I agree with most of #3 except for doing this, as I think it's going too far. I think if I saw it being done I'd say "WTF are they doing this for???" (and I think 99.99% of other programmers would say the same (what I'm trying to say is you'll just confuse other programmers for the most part with it)). I've never heard of a compiler needing this, and I think following it just on "rumor" is going waaay too far, asking for unnecessary mental overhead in developing. Additionally, if a compiler leaks macros/identifiers it shouldn't from one translation unit to another, it's worth reporting that bug to the compiler vendor, and expecting them to fix it.



Actually, #undefing your macros is still a good idea, in case someone gets antsy about build times and tries to deploy a unity build structure to your C/C++ project. Leaving macros defined all over the place can get incredibly painful in unity builds.

Are you and I talking about the same thing (#undef at the bottom of the .CPP files)? Like I said, I agree with most of #3 (cleaning up your macros is a good thing). But I think cleaning them up at the end of a source file is a waste of time and space, and I can't see how that would decrease compile times at all.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#14 ApochPiQ   Moderators   -  Reputation: 15698

Like
0Likes
Like

Posted 07 July 2012 - 09:05 PM

The whole idea of a "unity build" is to #include several of your .cpp files into one "master" translation unit, which does in fact help with compile times in some cases. (My personal feeling is that unity builds are a bandage over terrible header and dependency management issues, but that's another debate.)


Consider the following code:

// Foo.cpp
#define bool int

bool FooFunction() {
    return 1;
}

// Bar.cpp
bool BarFunction() {
    return true;
}

// Unity.cpp
#include "foo.cpp"
#include "bar.cpp"

This is typical of how unity builds are implemented. Clearly, in this example, you can expect the #define to cause havoc.

If you use unity builds, it's generally a very good idea to keep macros tightly scoped and #undef them as soon as possible. If that happens to be at the end of a .cpp file, so be it.

#15 Cornstalks   Crossbones+   -  Reputation: 6989

Like
0Likes
Like

Posted 07 July 2012 - 09:21 PM

*snip*

Ah, I see. I wasn't familiar with the term "unity build" (though I'm familiar with the concept; I'm more familiar with the term "amalgamation," thanks to SQLite) and had Unity (as in Unity3D) come to mind. Yes, I must agree then iff a unity build is being done. But L. Spiro was talking about macros spilling over from one translation unit to another, and in this normal workflow with multiple translation units I think it's pointless.

Edited by Cornstalks, 07 July 2012 - 09:25 PM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#16 L. Spiro   Crossbones+   -  Reputation: 13577

Like
0Likes
Like

Posted 07 July 2012 - 09:39 PM

I said to #undef them at the bottom but that was not to be taken too literally. I personally #undef them at the earliest possible moment, almost always being inside the same function in which they are created (even if I have a family of related functions in a row that end up redefining the same macro the same way), but I only wanted to mention the most common case where people “leak” macros, where you might #define some macro at the top of the .CPP, and then just let it go.

Definitely, if you are defining something inside a function, #undef at the end of the function, not the end of the file.

Also, having macros leak into other translation units (in a normal environment, not unity builds) is of course a special rare case, and is not the motivation for the #undef.
That is only a secondary point, since it is unlikely you will ever even encounter that.



L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#17 Acotoz   Members   -  Reputation: 73

Like
-4Likes
Like

Posted 07 July 2012 - 10:18 PM

#define: constant
global variable: variable

#18 Aardvajk   Crossbones+   -  Reputation: 5981

Like
0Likes
Like

Posted 08 July 2012 - 02:35 AM

#define: constant
global variable: variable


*Sigh*

const int i = 123; // constant
int i = 123; // global variable
#define i 123 // technically creates a literal, not a constant, everywhere it is replaced, with no meaningful name for the compiler to use

Edited by Aardvajk, 08 July 2012 - 02:36 AM.


#19 Matt-D   Crossbones+   -  Reputation: 1453

Like
3Likes
Like

Posted 08 July 2012 - 02:40 PM

In addition, it's worth noting that "const" has certain limitations; compare:
[source lang="cpp"]struct C{ inline static int getval() {return 4;}};const int MAX=1024;const int MIN=C::getval();[/source]
"MAX" is a constant integral expression (can be used as an array-size in array declarations, as a case label in switch statements, etc.), while "MIN" is not.
See: http://www.devx.com/...tion/33327/1954

In C++11 there's a new declaration specifier, "constexpr", which allows you to solve this problem and, for example, do this:
[source lang="cpp"]constexpr int getDefaultArraySize (int multiplier){ return 10 * multiplier;}int my_array[ getDefaultArraySize( 3 ) ];// perfectly legal, "getDefaultArraySize( 3 )" is a constant integral expression equal to 30 at compile-time[/source]

See: http://www.cprogramm...-constexpr.html

More:
http://en.cppreferen...guage/constexpr
http://cpptruths.blo...texpr-meta.html
http://thenewcpp.wor...1/14/constexpr/
http://kaizer.se/wik...onstexpr_foldr/

Edited by Matt-D, 08 July 2012 - 02:45 PM.


#20 Acotoz   Members   -  Reputation: 73

Like
-1Likes
Like

Posted 08 July 2012 - 06:30 PM


#define: constant
global variable: variable


*Sigh*

const int i = 123; // constant
int i = 123; // global variable
#define i 123 // technically creates a literal, not a constant, everywhere it is replaced, with no meaningful name for the compiler to use


Alright, let's have another case here.

what happens if I do this?

#define CYCLE for (int i = 0; i < 25; i++)

CYCLE will be defined by that little instruction, so that is not a literal, not a constant, not a variable.

Good luck




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS