Skip to main content
gamedev.net
🔒 Locked

#define problems

Started by Clovermite24 Aug 1, 2007 at 2:50 AM 14 replies 1.7k views
Original Post
Clovermite24
Clovermite24
Hey guys, I never know which forum to throw these questions under, so please just bear with me. I'm working on creating my first tetris game using DirectDraw7 (actual version is Directx10) and Microsoft Visual C++ 2005 Professional edition and I'm running into a weird issue where the compiler does not seem to be recognizing the #defines that I'm making (at least that's what I think the problem is). Code: In tetraMain.h

//DEFINES///////////////////////////////////////////
//Matrix values
#define MIN_X_MAP =0
#define MIN_Y_MAP =0
#define MAX_X_MAP = 7
#define MAX_Y_MAP = 7 

In tetraMain.cpp:

#include "tetraMain.h"

// GLOBALS ////////////////////////////////////////////////
int map[MAX_Y_MAP][MAX_X_MAP]; //this is line 36

Errors: line 36 : error C2143: syntax error : missing ']' before '=' line 36 : error C2440: 'initializing' : cannot convert from 'int' to 'int []' 1> There are no conversions to array types, although there are conversions to references or pointers to arrays line 36 : error C2143: syntax error : missing ';' before ']' This is just one example of where this strange behavior is occurring, so I can include more examples if anyone needs it. I'm guessing that the issue has to do with the settings I have Visual studio set to. So on that note: I have the character set on "Multi-byte" instead of "Unicode" so that DirectX will work properly. I have also added the "Directx\include" to the "Additional Include Directories" under the "C++" properties and "DirectX\lib\x86" to the "Additional Library Directories" under the "Linker" properties." I experimented with setting "Generate Preprocessed File" to "With Line Numbers" and "Without Line Numbers" (instead of no) and both of these eliminated my compile errors... but it also eliminated all compile errors so I don't see this as a legitimate solution (especially because the program won't link properly under this setting). Any suggestions?
btower
btower
You shouldn't use the = character when specifying the define values.
Your defines should look like this:

#define MIN_X_MAP 0
#define MIN_Y_MAP 0
#define MAX_X_MAP 7
#define MAX_Y_MAP 7


The preprocessor will literally put anything behind the define in your code.

So this line:
int map[MAX_Y_MAP][MAX_X_MAP]; //this is line 36

Becomes:
int map[= 7][= 7]; //this is line 36

That explains the error message your getting.
Crypter
Crypter
#define MIN_X_MAP =0#define MIN_Y_MAP =0#define MAX_X_MAP = 7#define MAX_Y_MAP = 7 


Take all of the assignments out here.
Driv3MeFar
Driv3MeFar
This is a great example of why #defines can be considered "evil". Since the preprocessor simply does inline text replacement, there is no error checking or type safety. In this example, there is no reason to use a #define over, say, a static constant:

static const int MIN_X_MAP = 0;
static const int MIN_Y_MAP = 0;
static const int MAX_X_MAP = 7;
static const int MAX_Y_MAP = 7;

Type safety is a wonderful thing.
kohlrak
kohlrak
the define should automatically translate it to whatever format... take below for example...

#define rawr 5

float rawr2=rawr;

rawr2 should have the float's equivalent of a 5 rather than an int's equivalent of a 5. Whenever you have a number un-suffixed (without decimal), it treats it as a "const int" variable. When you try to throw it anywhere, it just type casts it for you. By default if it ends with f, it's a float. By default if it contains a decimal point, but not ending in an f, it's a double.
Crypter
Crypter
Quote:
Original post by kohlrak
the define should automatically translate it to whatever format...


The preprocessor replaces the text in #define'd constants. Depending on the
generated synthax, the compilier may be able to convert it, however, the
preprocessor does not.

It is simple text replacement for the preprocessor.

Quote:

This is a great example of why #defines can be considered "evil".

QFE.
Driv3MeFar
Driv3MeFar
Quote:
Original post by kohlrak
the define should automatically translate it to whatever format... take below for example...

#define rawr 5

float rawr2=rawr;

rawr2 should have the float's equivalent of a 5 rather than an int's equivalent of a 5. Whenever you have a number un-suffixed (without decimal), it treats it as a "const int" variable. When you try to throw it anywhere, it just type casts it for you. By default if it ends with f, it's a float. By default if it contains a decimal point, but not ending in an f, it's a double.


The dumb text replacement done by the preprocessor can lead to some insidious bugs. Take, for example (and this is from game code I've worked with, only more pseudo-cody), the following:
#define FPS 60//ElapsedTime in secondsbool IsTimeToRender(float ElapsedTime){    if ( (ElapsedTime >= 1 / FPS)    {        return true;    }    return false;}

Simple enough. If 1/60th of a second or more has elapsed, then it's time to draw a new frame. However, since this is equivalent to:
//ElapsedTime in secondsbool IsTimeToRender(float ElapsedTime){    if ( (ElapsedTime >= 1 / 60)    {        return true;    }    return false;}


An integer division is performed, and the results are:
if (ElapsedTime >= 0)
{
...
}

Of course, since you have no idea that FPS is being treated as an int (after all, FPS doesn't have a type, it's just the number 60), this can be a nasty little bug to track down, whereas if you knew that you were dividing 1 by a const int, it would be easy to spot and fix.

Or similarly, consider:

#define FrameDrawTime 1 / 60

...
if (ElapsedTime >= FrameDrawTime)
{
...
}

This looks harmless, but the results are the same (an integer division, and resulting comparison against 0). If instead you had:
static const float FrameDrawTime = 1 / 60;
You could take a look at FrameDrawTime's value in the debugger, see it was 0, and deduce the problem.
kohlrak
kohlrak
It's being compared to a float, therefor, it should be passed to the FPU to be compared on the FPU. Now, whether or not it is passed first and then calculated then checked or calculated then passed then checked depends on the compiler.
Way Walker
Way Walker
Quote:
Original post by Driv3MeFar
This is a great example of why #defines can be considered "evil".


No, it's not. This is a great example of not understanding how defines work. It'd be similar to trying to write:

int MIN_X_MAP = const 0;

Quote:

Since the preprocessor simply does inline text replacement, there is no error checking or type safety.


Produced an error just fine, here, and type safety doesn't even enter into it.

Quote:

In this example, there is no reason to use a #define over, say, a static constant


Mostly true. Interfacing with code written in C is a reason, but an unlikely one.

As for your FPS example, FPS is usually presented (in my experience) as an integer. That is, you count the number of frames that have elapsed this second. Thus, using an int to represent it doesn't seem unreasonable, so 1/FPS will still produce 0. In either case, if you wanted that form, you'd have to write 1./FPS or similar. I haven't found this to be difficult to track down in either case. The first thing I check is the values being compared and, as you point out, that should be enough to deduce the problem.

Don't get me wrong, you shouldn't use #define constants in C++, but that has much more to do with them ignoring namespaces than anything else. #define macros are much more troublesome.
ToohrVyk
ToohrVyk
Quote:
Original post by kohlrak
It's being compared to a float, therefor, it should be passed to the FPU to be compared on the FPU.


This is correct (well, as long as there is an FPU to begin with, as opposed to software emulation or built-in support). However, "it", in your sentence, refers to the result of the expression 1 / 60, which is 0.

Quote:
Now, whether or not it is passed first and then calculated then checked or calculated then passed then checked depends on the compiler.


The value of 1 / 60 is defined by the standard as being 1° independent of the context that it is evaluated in and 2° equal to the euclidean division of 1 by 60, which is 0. This value will then be converted to whatever type is required by >=, which in this case is the floating-point value 0.0f.
kohlrak
kohlrak
Quote:
Don't get me wrong, you shouldn't use #define constants in C++, but that has much more to do with them ignoring namespaces than anything else. #define macros are much more troublesome.


You dislike constants as defines. You dislike macro as defines... So what do you propose we do with defines?

ToohrVyk
ToohrVyk
Quote:
Original post by kohlrak
You dislike constants as defines. You dislike macro as defines... So what do you propose we do with defines?


Conditional compiling and include guards are pretty good applications of preprocessor definitions.

Julian90
Julian90
Quote:
Original post by ToohrVyk
Quote:
Original post by kohlrak
You dislike constants as defines. You dislike macro as defines... So what do you propose we do with defines?


Conditional compiling and include guards are pretty good applications of preprocessor definitions.


Local defines for code generation can also be justified, the type of stuff BOOST_PP is designed for.
Clovermite24
Clovermite24
Wow I can't believe I didn't think of that.

Thanks a million guys, much appreciated. I knew this was a really simple problem, I just couldn't figure it out for the life of me, but that's what I get for spending so much time READING about coding without getting around to actually doing it.

Out of curiousity, did I place this question correctly, or should I have put it up in the "For Beginners?"

Zahlman
Zahlman
Quote:
Original post by kohlrak
It's being compared to a float, therefor, it should be passed to the FPU to be compared on the FPU. Now, whether or not it is passed first and then calculated then checked or calculated then passed then checked depends on the compiler.


Absolutely, 100% wrong. You can't "pass" an uncalculated value to the FPU! (Hint: how would it be represented?) The integer division must occur first; it's a syntax rule of the language. Order of operations, you know. Mathematical operators happen before relational ones.

Quote:
Original post by kohlrak
Quote:
Don't get me wrong, you shouldn't use #define constants in C++, but that has much more to do with them ignoring namespaces than anything else. #define macros are much more troublesome.


You dislike constants as defines. You dislike macro as defines... So what do you propose we do with defines?


#defines are a text substitution hack. You should use them only when they are the only thing that will do what you need, because anything that has even the tiniest "understanding of the language" will obviously do at least as good (and usually a much better) job.

Things like:

- actual const identifiers (they exist for a reason :) They have a scope, a type and an identity: you can take their addresses.
- inline functions. If the reason you don't want to write a function to do something that happens several times in the code is because you "don't want to pay the overhead of a function call", you are living wayyyyyyyyyyyyyyyyyyy in the past.
XSlinger
XSlinger
Quote:
Original post by Driv3MeFar
This is a great example of why #defines can be considered "evil". Since the preprocessor simply does inline text replacement, there is no error checking or type safety. In this example, there is no reason to use a #define over, say, a static constant:

static const int MIN_X_MAP = 0;
static const int MIN_Y_MAP = 0;
static const int MAX_X_MAP = 7;
static const int MAX_Y_MAP = 7;

Type safety is a wonderful thing.


Noob question: Why do you declare the constants static?

Topic Locked

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

Sign in to reply to this topic.