Click here to Skip to main content
15,893,564 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,
I am trying to compile this piece of code found below.
However, I got an error saying "Initialization value must be constant expression."on every line of iteminfo_fields, weaponinfo_fields and projectileinfo_fields definitions, except at the last line of each "{NULL, 0, 0}"
I am guessing it is from ITEMINFO_OFS(), WEAPON_OFS(), PROJECTILE_OFS().

I am trying to understand these three lines:
#define WEAPON_OFS(x) (size_t)&(((weaponinfo_t *)0)->x)
#define PROJECTILE_OFS(x) (size_t)&(((projectileinfo_t *)0)->x)
#define ITEMINFO_OFS(x)	(size_t)&(((iteminfo_t *)0)->x)


But, I really cannot understand how they work...???
I need help dissecting them. Can anyone read them and rewrite them in a simpler form?
#define WEAPON_OFS(x) (size_t)&(((weaponinfo_t *)0)->x)
#define PROJECTILE_OFS(x) (size_t)&(((projectileinfo_t *)0)->x)
#define ITEMINFO_OFS(x)	(size_t)&(((iteminfo_t *)0)->x)

fielddef_t iteminfo_fields[] =
{
{"name", ITEMINFO_OFS(name), FT_STRING},
{"model", ITEMINFO_OFS(model), FT_STRING},
{"modelindex", ITEMINFO_OFS(modelindex), FT_INT},
{"type", ITEMINFO_OFS(type), FT_INT},
{"index", ITEMINFO_OFS(index), FT_INT},
{"respawntime", ITEMINFO_OFS(respawntime), FT_FLOAT},
{"mins", ITEMINFO_OFS(mins), FT_FLOAT|FT_ARRAY, 3},
{"maxs", ITEMINFO_OFS(maxs), FT_FLOAT|FT_ARRAY, 3},
{NULL, 0, 0}
};
//weapon definition
static fielddef_t weaponinfo_fields[] =
{
{"number", WEAPON_OFS(number), FT_INT},	//weapon number
{"name", WEAPON_OFS(name),FT_STRING},	//name of the weapon
{"level", WEAPON_OFS(level), FT_INT},
{"model", WEAPON_OFS(model), T_STRING},	//model of the weapon
{"weaponindex", WEAPON_OFS(weaponindex), FT_INT},//index of weapon in inventory
{"flags", WEAPON_OFS(flags), FT_INT},//special flags
{"projectile", WEAPON_OFS(projectile), FT_STRING},//projectile used by the weapon
{"numprojectiles", WEAPON_OFS(numprojectiles), FT_INT},	//number of projectiles
{"hspread", WEAPON_OFS(hspread), FT_FLOAT},//horizontal spread of projectiles (degrees from middle)
{"vspread", WEAPON_OFS(vspread), FT_FLOAT},//vertical spread of projectiles (degrees from middle)
{"speed", WEAPON_OFS(speed), FT_FLOAT},	//speed of the projectile (0 = instant hit)
{"acceleration", WEAPON_OFS(acceleration), FT_FLOAT},//"acceleration" * time (in seconds) + "speed" = projectile speed
{"recoil", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3},//amount of recoil the player gets from the weapon
{"offset", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3},//projectile start offset relative to eye and view angles
{"angleoffset", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles
{"extrazvelocity", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets
{"ammoamount", WEAPON_OFS(ammoamount), FT_INT},	//ammo amount used per shot
{"ammoindex", WEAPON_OFS(ammoindex), FT_INT},	//index of ammo in inventory
{"activate", WEAPON_OFS(activate), FT_FLOAT},	//time it takes to select the weapon
{"reload", WEAPON_OFS(reload), FT_FLOAT},	//time it takes to reload the weapon
{"spinup", WEAPON_OFS(spinup), FT_FLOAT},	//time it takes before first shot
{"spindown", WEAPON_OFS(spindown), FT_FLOAT},	//time it takes before weapon stops firing
{NULL, 0, 0, 0}
};

//projectile definition
static fielddef_t projectileinfo_fields[] =
{
{"name", PROJECTILE_OFS(name), FT_STRING},//name of the projectile
{"model", WEAPON_OFS(model), FT_STRING},//model of the projectile
{"flags", PROJECTILE_OFS(flags), FT_INT},//special flags
{"gravity", PROJECTILE_OFS(gravity), FT_FLOAT},	//amount of gravity applied to the projectile [0,1]
{"damage", PROJECTILE_OFS(damage), FT_INT},//damage of the projectile
{"radius", PROJECTILE_OFS(radius), FT_FLOAT},//radius of damage
{"visdamage", PROJECTILE_OFS(visdamage), FT_INT},//damage of the projectile to visible entities
{"damagetype", PROJECTILE_OFS(damagetype), FT_INT},//type of damage (combination of the DAMAGETYPE_? flags)
{"healthinc", PROJECTILE_OFS(healthinc), FT_INT},//health increase the owner gets
{"push", PROJECTILE_OFS(push), FT_FLOAT},//amount a player is pushed away from the projectile impact
{"detonation", PROJECTILE_OFS(detonation), FT_FLOAT},//time before projectile explodes after fire pressed
{"bounce", PROJECTILE_OFS(bounce), FT_FLOAT},	//amount the projectile bounces
{"bouncefric", PROJECTILE_OFS(bouncefric), FT_FLOAT}, //amount the bounce decreases per bounce
{"bouncestop", PROJECTILE_OFS(bouncestop), FT_FLOAT},//minimum bounce value before bouncing stops
//recurive projectile definition??
{NULL, 0, 0, 0}
};

Note:
My situation is a bit complicated at the moment. However,
I do not know the name of the compiler. The environment is Linux tho.
It is not my code, but I need to have it compile.
Posted
Comments
LloydA111 13-Apr-11 19:44pm    
You will probably be using GCC.

The 3 macros compute the field offset of a given data member within a structure.
For example:
struct MY_STRUCT
{
    //a is an int, so it takes 4 bytes
    int a;
    //b is a float, so it takes 4 bytes
    float b;
    //c is a char, so it takes 1 byte
    char c;
    ...
};
void ComputeFieldOffsets()
{
    //to compute the field offset for each data member
    //you can do something like that:
    //declare a variable from the structure
    MY_STRUCT myStruct;
    //get the address of the struct
    void* pBase = (void*)&myStruct;
    //get the address of field a
    void* pA =(void*)&myStruct.a;
    //get the offset of a
    size_t offestA = (size_t)pA - (size_t)pBase;
    //Since a is the first field in the struct, offsetA equals 0
    //
    //get the address of field b
    void* pB =(void*)&myStruct.b;
    //get the offset of b
    size_t offestB = (size_t)pB - (size_t)pBase;
    //Since b is declared just after a, and a is 4 bytes, offsetB equals 4
    //actually it can be different, especially if you are running on a 64 bits system
    //because the compiler decides how to store the data for optimizations
    //
    //get the address of field c
    void* pC =(void*)&myStruct.c;
    //get the offset of c
    size_t offestC = (size_t)pC - (size_t)pBase;
    //Since c is declared just after b, and b is 4 bytes, offsetC equals 8
    //
    //and so on
    ...
}

The guy who wrote the macro wanted to compute these offsets. But instead of declaring a struct and taking its address, he used a NULL pointer (the 0 inside the macro definition).
Compared to my example, it is as if you replaced pBase pointer by a NULL pointer:
size_t offestA = (size_t)pA - (size_t)pBase;
//or
size_t offestA = (size_t)(&myStruct.a) - (size_t)pBase;
//or
size_t offestA = (size_t)(&((MY_STRUCT*)pBase)->a) - (size_t)pBase;
//and if you replace pBase by 0
size_t offestA = (size_t)(&((MY_STRUCT*)0)->a) - (size_t)0;
//or
size_t offestA = (size_t)(&((MY_STRUCT*)0)->a);

And the guy wanted to write a function which could return the field offset for any field name, so he just made the field name a parameter of the macro: x.
To sumerize:
- WEAPON_OFS(number) returns the field offset of number within the weaponinfo_t struct
- PROJECTILE_OFS(model) returns the field offset of model within the projectileinfo_t struct
- and so on...

He probably had a good reason to code these things, but I wouldn't recommand to take such habits... This is kind of "dirty programming".
My opinion is he made this to make his data file more flexible to changes: he probably stores all members with their description, so they can be reloaded even if the file format changes...
 
Share this answer
 
Comments
Albert Holguin 13-Apr-11 17:45pm    
just like you said, looks like its coded to be easily expandable... i can see how painful this would be for someone to interpret. excellent explanation oliver, my 5!
Olivier Levrey 14-Apr-11 3:21am    
Thank you Albert.
coffeenet 14-Apr-11 5:11am    
Thank you so much Olivier for that hefty explanation!! Are you a teacher?
Just to make sure I got this right, if replaced it should look something like this:
From
{"name", ITEMINFO_OFS(name), FT_STRING},
To
{"name", (size_t)&(((iteminfo_t *)0)->name), FT_STRING},
Right?

Btw, I hear the term "dirty programming" a lot. What IS "dirty" and not "dirty" programming? Or what makes this and that? And why do you consider the above code "dirty"?
Olivier Levrey 14-Apr-11 6:04am    
No I am not a teacher ;) Yes you are right, your code snippet is correct. Dirty programming often depends on your own feelings. Somebody would say "woah this is great" because it solves a difficult problem, even though the code is hard to understand. For me this code is dirty mainly because it heavily relies on macros (macros must be used very carefully) and is not easy to understand. If you don't understand the code, it is hard to maintain it, so easier to do mistakes. And even though you would be very clever and would understand everything, you should think about the people who will use your code: maybe those people will not understand your code... I think the guy wanted to write a generic function to load/save the structures from/into a file, and didn't want to rewrite the functions each time he would change the structures. For example, the saving function would save each entry in the iteminfo_fields array: this array contains all the fields to save (name of the field, type of the field, where to find the value of the field within the structure). But there are other (and more readable) ways to acheive this.
coffeenet 14-Apr-11 7:58am    
Your explanation was really good!
I've rewritten this code snippet, but still I'm getting the same error as before, "Initialization value must be constant expression."
<pre>
#define WEAPON_OFS(x) (size_t)&(((weaponinfo_t *)0)->x)
#define PROJECTILE_OFS(x) (size_t)&(((projectileinfo_t *)0)->x)

//weapon definition
static fielddef_t weaponinfo_fields[] =
{
//{"number", WEAPON_OFS(number), FT_INT}, //weapon number
{"number", (size_t)&(((weaponinfo_t *)0)->number), FT_INT}, //weapon number
</pre>
I've set the second value, WEAPON_OFS(number), with a 0, and the error disappeared.
Do you have any suggestions on to why I am getting this error? And if you know how to fix it, I would be happy to hear it too : D
The C standard provides offsetof that you should use instead of the NULL->...
 
Share this answer
 
Looks to me like it's defining a field offset based on the type of value that's represented by the specified field name.
 
Share this answer
 
Comments
Olivier Levrey 13-Apr-11 12:56pm    
Exactly. But you don't help OP much about understanding it...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900