Sign in to follow this  
walkingcarcass

Wierd preprocessor error

Recommended Posts

walkingcarcass    116
Hi all. I have the following C++ code:
const static int GRAPES = MAX_GRAPE+1;
#define banter(ID,MODE) (ID*GRAPES + MODE)

const static Grape EYEBALL 	= NUMPTY;
const static Grape MINE_READER	= NUMPTY;

static const unsigned int MINER_QUERY	= banter(30, MINE_READER);
static const unsigned int MINER_CLEAR	= banter(31, MINE_READER);
static const unsigned int MINER_NOT_CLEAR = banter(32, MINE_READER);
static const unsigned int MINER_FIRE	= banter(33, MINE_READER);
static const unsigned int MINER_RESET	= banter(34, MINE_READER);
	
static const unsigned int EYEBALL_CALIBRATE = banter(40, EYEBALL);
static const unsigned int EYEBALL_SEND_ALL = banter(41, EYEBALL);


static const unsigned int NUMPTY_SENSOR_STATUS	= banter(0, NUMPTY);
static const unsigned int NUMPTY_SENSOR_LIST	= banter(1, NUMPTY);
static const unsigned int NUMPTY_MINE_STATUS	= banter(2, NUMPTY);
static const unsigned int NUMPTY_MINE_LIST	= banter(3, NUMPTY);
static const unsigned int NUMPTY_STRATEGY	= banter(4, NUMPTY);
static const unsigned int NUMPTY_START		= banter(5, NUMPTY);
static const unsigned int NUMPTY_STOP		= banter(6, NUMPTY);
static const unsigned int NUMPTY_GO_TO		= banter(7, NUMPTY);
static const unsigned int NUMPTY_ACT		= banter(8, NUMPTY);
static const unsigned int NUMPTY_RESET		= banter(9, NUMPTY);
static const unsigned int NUMPTY_TIDOS_HALTED	= banter(10, NUMPTY);
static const unsigned int NUMPTY_REFUSED	= banter(11, NUMPTY);
static const unsigned int NUMPTY_INTERRUPTED	= banter(12, NUMPTY);
static const unsigned int NUMPTY_FINISHED	= banter(13, NUMPTY);
static const unsigned int NUMPTY_FORGET		= banter(14, NUMPTY);
static const unsigned int NUMPTY_MINE_AT	= banter(15, NUMPTY);
static const unsigned int NUMPTY_TIDOS_AT	= banter(16, NUMPTY);
static const unsigned int NUMPTY_PERSON_AT	= banter(17, NUMPTY);


I was getting odd results, so I did "g++ -E" and got the following dump from the preprocessor:
static const unsigned int MINER_QUERY = (0*GRAPES + MINE_READER);
static const unsigned int MINER_CLEAR = (1*GRAPES + MINE_READER);
static const unsigned int MINER_NOT_CLEAR = (2*GRAPES + MINE_READER);
static const unsigned int MINER_FIRE = (3*GRAPES + MINE_READER);
static const unsigned int MINER_RESET = (4*GRAPES + MINE_READER);


static const unsigned int EYEBALL_CALIBRATE = (0*GRAPES + EYEBALL);
static const unsigned int EYEBALL_SEND_ALL = (1*GRAPES + EYEBALL);

static const unsigned int NUMPTY_SENSOR_STATUS = (0*GRAPES + NUMPTY);
static const unsigned int NUMPTY_SENSOR_LIST = (1*GRAPES + NUMPTY);
static const unsigned int NUMPTY_MINE_STATUS = (2*GRAPES + NUMPTY);
static const unsigned int NUMPTY_MINE_LIST = (3*GRAPES + NUMPTY);
static const unsigned int NUMPTY_STRATEGY = (4*GRAPES + NUMPTY);
static const unsigned int NUMPTY_START = (5*GRAPES + NUMPTY);
static const unsigned int NUMPTY_STOP = (6*GRAPES + NUMPTY); static const unsigned int NUMPTY_GO_TO = (7*GRAPES + NUMPTY);
static const unsigned int NUMPTY_ACT = (8*GRAPES + NUMPTY);
static const unsigned int NUMPTY_RESET = (9*GRAPES + NUMPTY);
static const unsigned int NUMPTY_TIDOS_HALTED = (10*GRAPES + NUMPTY);
static const unsigned int NUMPTY_REFUSED = (11*GRAPES + NUMPTY);
static const unsigned int NUMPTY_INTERRUPTED = (12*GRAPES + NUMPTY);
static const unsigned int NUMPTY_FINISHED = (13*GRAPES + NUMPTY);
static const unsigned int NUMPTY_FORGET = (14*GRAPES + NUMPTY);
static const unsigned int NUMPTY_MINE_AT = (15*GRAPES + NUMPTY);
static const unsigned int NUMPTY_TIDOS_AT = (16*GRAPES + NUMPTY);
static const unsigned int NUMPTY_PERSON_AT = (17*GRAPES + NUMPTY);


The numbers 30, 31, 32, ..., for the MINE_READER section and the 40, 41 from the EYEBALL section have had their first digits dropped by the preprocessor! This is especially weird since the NUMPTY ones are fine. I don't expect much help on this, but does anyone have any idea why this is happening? I'm using gcc-3.4.4

Share this post


Link to post
Share on other sites
LessBread    1415
#define banter(ID,MODE) (ID*GRAPES + MODE)

Try wrapping the macro arguments in parens and casting to unsigned int, like so:

#define BANTER(id,mode) (unsigned int)((id)*GRAPES + (mode))

Also note that preprocessor macros are typically uppercased to distinguish them from function calls.

Share this post


Link to post
Share on other sites
Kalazart    148
I copied your code and done -E with g++. I got it right:


const static int GRAPES = MAX_GRAPE+1;


const static Grape EYEBALL = NUMPTY;
const static Grape MINE_READER = NUMPTY;

static const unsigned int MINER_QUERY = (30*GRAPES + MINE_READER);
static const unsigned int MINER_CLEAR = (31*GRAPES + MINE_READER);
static const unsigned int MINER_NOT_CLEAR = (32*GRAPES + MINE_READER);
static const unsigned int MINER_FIRE = (33*GRAPES + MINE_READER);
static const unsigned int MINER_RESET = (34*GRAPES + MINE_READER);

static const unsigned int EYEBALL_CALIBRATE = (40*GRAPES + EYEBALL);
static const unsigned int EYEBALL_SEND_ALL = (41*GRAPES + EYEBALL);

// etc...


Using GCC 3.4.5 on mingw.

Share this post


Link to post
Share on other sites
NotAYakk    876
Fix your style, as the above posted said. =) I got rather confused when you used lower case for macros and upper case for non-macros!

Try to reduce your problem down to a small, compiling bit of code that shows the error. As it stands, we have to make up our own definition for half of your symbols.

Next:
#define banter(ID,MODE) (ID*GRAPES + MODE)
why is this a macro? Why can't it be:
namespace {
inline unsigned int banter(unsigned int id, unsigned int mode) {
return id * GRAPES + mode;
}
}

?

Share this post


Link to post
Share on other sites
walkingcarcass    116
Quote:
Original post by NotAYakk
#define banter(ID,MODE) (ID*GRAPES + MODE)
why is this a macro? Why can't it be:
namespace {
inline unsigned int banter(unsigned int id, unsigned int mode) {
return id * GRAPES + mode;
}
}

?


AFAIK, you can't initialise global consts with function calls.

Parentheses fixed it, thanks. Can't imagine why.

Share this post


Link to post
Share on other sites
NotAYakk    876
Quote:
Original post by walkingcarcass
Quote:
Original post by NotAYakk
#define banter(ID,MODE) (ID*GRAPES + MODE)
why is this a macro? Why can't it be:
namespace {
inline unsigned int banter(unsigned int id, unsigned int mode) {
return id * GRAPES + mode;
}
}

?


AFAIK, you can't initialise global consts with function calls.


You can initialize global consts with function calls.

Don't use macros unless you really have to. As you have just noticed they are evil, random and they suck. =)

Quote:
Parentheses fixed it, thanks. Can't imagine why.


Case in point. =)

Share this post


Link to post
Share on other sites
snk_kid    1312
Yes you can, i also serious suggest using an inline function, by the way the keyword static on globals (or namespace level) variables or free-functions is deprecated in C++ in favour of anonymous namespaces so don't do it because there icky for number of reasons.

Share this post


Link to post
Share on other sites
NotAYakk    876
Be careful with inline functions in .cpp files. Heck be careful with them in general.

Place them in anonymous namespaces. Like this:
namespace {
inline double size(my_data_type* data) {
...
};
};


If there are two inline functions with identical signatures compiled together, either of them can be silently discarded without checking to make certain they aren't different.

This won't bite you that often, but I've had it cause serious problems.

An example of this problem:

// file a.cpp
class test {
int x;
int y;
test():x(55), y(10) {}; // methods defined like this are implicitly inlined
};
// file b.cp
class test {
void* foo;
test(): foo(0) {}
};


The signature of the two two constructors above are identical, and they are implicitly inlined because of how they are defined.

Constructing a test object now does seriously random stuff, up to and including memory corruption.

So:
1> Use anonymous namespace {}s liberally.
2> avoid macros if you can (the issues macros can cause make the above evil look positively friendly)
3> Use non-anonymous namespaces liberally.
4> And, as an aside, avoid doing:
using namespace x;

in a header file. If you must import symbols, do it explicitly:
using x::foo;
using x::bar;

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this