C mystery?

Discuss programming topics for the various GPL'd game engine sources.
Post Reply
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

C mystery?

Post by Baker »

Is there any reason the following 2 shouldn't be essentially equivalent?

Case 1:
extern const fields_t* fieldmap

versus

Case 2:
extern const fields_t fieldmap[46];

I do this and "Case 1" explodes with fieldmapname being invalid. But if I do "Case 2" I'm fine.

Code: Select all

	const char* fieldmapname = fieldmap[0].fieldname;  <---- this ends up with invalid pointer in Case 1
I guess I am missing some obscure reason "Case 1" and "Case 2" aren't equivalent. Fieldmap is not of a known defined size, so I can't do "extern const fields_t fieldmap[46]" because the 46 is not known at compile time.

Now, I can just do "extern const fields_t fieldmap[1]" and reference outside member number 0 thru X, but I don't want to write hacky code like that.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: C mystery?

Post by Baker »

I think I was doing something "bad".

I had fieldmap [] defined as such ...

Code: Select all

fields_t fieldmap [] = // System defaults
{
// name stringvalue argnum <-- argum for entities_add command, set with entities_fields command
	{ "INVALID",	"NONE",			SPECIAL_INVALID,EVAL_TEXT64,	0,	0},
	{ "name",		"NONE",			SPECIAL_PTRREF,	EVAL_TEXT64,	1,	offsetof(entity_t, _name)}, // Special -> name
	{ "parent_name","NONE",			SPECIAL_RESOLVE,EVAL_TEXT64,	0,	offsetof(entity_t, _parent_name)}, // Special -> parent_name (parent, child_count, child_max_nest_level)
	{ "model",		"NONE",			SPECIAL_MGR_M,	EVAL_TEXT64,	2,	offsetof(entity_t, _model)}, // Special -> model_url, model_manager_slot
	{ "texture",	"NONE",			SPECIAL_MGR_T,	EVAL_TEXT64,	3,	offsetof(entity_t, _texture)}, // Special -> texture_url, texture_manager_slot
...
But was externing as such:

extern const fields_t* fieldmap;

And I think that was causing the issue. Eventually fieldmap was going to be dynamically allocated, but I hadn't done that yet and I didn't think my extern would hurt anything but apparently it did.

[Yeah, I'm playing around and do some crazy stuff. Investigating inner mysteries ... ]
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: C mystery?

Post by Spike »

yes there's a difference.

to read a single word in pseudo asm:
pointer:
mov [&ptr] -> reg
mov [reg+offset] -> result

array:
mov [&arr+offset] -> result

square brackets denote a memory reference.

While the syntax is mostly the same, they are not identical at a hardware level. 'const' doesn't really mean anything, other than as purely a hint (which can be used for optimisations and generating warnings/errors).

You can always define eg:
extern char foo[];
that would be valid, due to the extern not requiring size info, but beware that it breaks sizeof in any file where foo was not formally sized.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: C mystery?

Post by Baker »

Spike wrote:You can always define eg:
extern char foo[];
that would be valid, due to the extern not requiring size info, but beware that it breaks sizeof in any file where foo was not formally sized.
Ah I didn't know I could do that. And thanks for asm explanation of the difference.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: C mystery?

Post by Spike »

to get around the sizeof issue, most people just put an entry on the end with everything set to null or something otherwise invalid, as a marker to know when its reached the end.
if you really need a pointer, you can always do extern mytype *fooptr; mytype fooarr[] = {{foo}}; mytype *fooptr = fooarr; with a few added consts, which would of course give a pre-initialised pointer to the same address that the array is located at.
note that (fooarr) and (&fooarr) will both return the same address. Because arrays are weeird, like function pointers really.

char* has to always be loaded before use, while an array's offset can be hardcoded within the instructions that use it.
this means that arrays result in larger individual instructions, while pointers take an extra instruction, the other references are typically smaller by a few bytes (especially on amd64)
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: C mystery?

Post by Baker »

Can I expect single byte data types, like char or unsigned char, to hold up to my previous conception that:

char* somevar;

and

char somevar[20];

... can be expected to be reliably the same from a referencing standpoint? And the behavior you described above is typically limited to struct behavior?

I ask because I have never experienced a situation where either of these has failed me:

char* something = somevar; // Where char somevar[20];
byte* something = somedata; // Where byte is unsigned char and byte somedata[20];

Obviously I'm only talking about to trusting that the reference works, clearly sizeof is lost.

[I know the perils of sizeof. Perhaps not all of them, but I am super-paranoid about it know the few occasions that I can expect to trust it. I also know the sizeof a struct can vary from expectations, you and others explained when I discovered "the padding" that cannot be trusted to operate in any specific way.]
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: C mystery?

Post by Spike »

huh? a pointer is always 4 bytes (8 bytes on a 64bit machine).
while a 20-element byte array is of course 20 bytes...
a pointer to a 20-element byte array is still just 4 bytes. there's just an extra 20 bytes which is not part of the pointer itself, but part of what it points to.

just because the syntax is the same doesn't mean that the hardware instructions are, which means you cannot mix and match them in different C files, because the hardware representation would conflict between modules / .c files.

If you never take the address of the pointer/array, then the *syntax* is the same and you can freely change the definition between pointer and array - so long as you never use sizeof and the prototype of it matches in every single .c file.

pointer arithmatic works just fine regardless of whether the data is at a constant location (array) or a variable location (pointer). The syntax differences really only come when you take the address of a constant vs variable, while the hardware always cares about the difference. Storing the constant (array) address of the data inside a variable (pointer, even if defined const) is no different from storing the number 5 in a an int, and will allow the hardware to access your fixed-address array data through a variable.

When you have position independant code (more common in linux), the 'constant' addresses are calculated based upon the program counter offset. the maths is along the lines of (&dataaddress - baseaddressofinstruction) + instructionpointer, the first two parts being a constant and the second part being a register of some kind, though on x86 there'll be some additional offsets because you cannot directly reference the instruction pointer register.

Remember - a pointer is an integer variable, accessed through the value stored in that integer. An array is an actual chunk of memory, accessed through the constant address of the first byte.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: C mystery?

Post by Baker »

Spike wrote: which means you cannot mix and match them in different C files, because the hardware representation would conflict between modules / .c files.
That was the piece I was missing while trying to sort out the implications of this in my head.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply