#1 Members - Reputation: 246
Posted 05 July 2012 - 04:50 PM
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?
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
#2 Members - Reputation: 2408
Posted 05 July 2012 - 04:58 PM
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 Moderators - Reputation: 7663
Posted 05 July 2012 - 04:59 PM
#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.
[Work - ArenaNet] [Epoch Language] [Scribblings] [Journal - peek into my shattered mind]
#4 Members - Reputation: 269
Posted 05 July 2012 - 05:01 PM
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 Members - Reputation: 246
Posted 05 July 2012 - 05:31 PM
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 Members - Reputation: 269
Posted 05 July 2012 - 05:42 PM
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.So basically you're all saying that if I can use a global constant rather than a #define, I should?
#7 Members - Reputation: 817
Posted 06 July 2012 - 04:53 AM
like #define max did all the time for me...
if you don't plan to ctrl-r replace-all-text, don't use #define.
My Page davepermen.net | My Music on Bandcamp and on Soundcloud
#9 Crossbones+ - Reputation: 5172
Posted 07 July 2012 - 08:40 AM
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.
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
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums
#10 Members - Reputation: 216
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 Moderator* - Reputation: 5392
Posted 07 July 2012 - 06:29 PM
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.so #undef at the bottom of the .CPP files is a good idea.
+1. In addition: "Each name that begins with an underscore is reserved to the implementation for use as a name in the
__ (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.
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.
#12 Moderators - Reputation: 7663
Posted 07 July 2012 - 08:44 PM
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.
so #undef at the bottom of the .CPP files is a good idea.
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.
[Work - ArenaNet] [Epoch Language] [Scribblings] [Journal - peek into my shattered mind]
#13 Moderator* - Reputation: 5392
Posted 07 July 2012 - 08:57 PM
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 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.
so #undef at the bottom of the .CPP files is a good idea.
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.
#14 Moderators - Reputation: 7663
Posted 07 July 2012 - 09:05 PM
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.
[Work - ArenaNet] [Epoch Language] [Scribblings] [Journal - peek into my shattered mind]
#15 Moderator* - Reputation: 5392
Posted 07 July 2012 - 09:21 PM
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.*snip*
Edited by Cornstalks, 07 July 2012 - 09:25 PM.
#16 Crossbones+ - Reputation: 5172
Posted 07 July 2012 - 09:39 PM
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
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
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums
#18 Members - Reputation: 2408
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 Members - Reputation: 843
Posted 08 July 2012 - 02:40 PM
[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 Members - Reputation: 73
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






