This morning we found an old chunk of code that was causing a library call to crash.
struct fred
{
int a;
int b;
int c;
};
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(fred) * MAX_SIZE+1 );
It appears that the sizeof(fred) may have been the full array size, rather than the structure size, as it was overwriting a great deal of memory.
The fact that it compiled without warning on several different systems seemed odd.
Is there a correct semantic for this case where the type and variable name are colliding? or is this some sort of undefined behavior? or just a defect?
Number one would be, don't do this as it's confusing - but you've already discovered this.
The variable hides the name of the struct, but you can still use struct fred
to refer to the type.
e.g.
fred fred[MAX_SIZE+1];
memset( fred, 0, sizeof(struct fred) * (MAX_SIZE+1) );
Alternatively, why not just use the size of the complete object. That way your memset
call is robust in the face of changes to either the array size or type. You can do:
memset( fred, 0, sizeof fred );
You must have the parentheses when using a type id with sizeof
but it's not needed when you use an object.
Shouldn't this be sizeof(fred)*(MAX_SIZE+1) since your array is MAX_SIZE+1 long?
The latest declaration takes precedence:
[C++03: 9.1/2]:
A class definition introduces the class name into the scope where it is defined and hides any class, object, function, or other declaration of that name in an enclosing scope (3.3). If a class name is declared in a scope where an object, function, or enumerator of the same name is also declared, then when both declarations are in scope, the class can be referred to only using an elaborated-type-specifier (3.4.4).
An elaborated-type-specifier is when you stick struct
or class
at the front of the type; this effectively disambiguates it, though, strictly speaking, and due to the above cited rule, the lookup was never really ambiguous in the first place.
So:
void foo()
{
struct bar {};
bar bar[5];
memset(bar, 0, sizeof(bar));
// ^^^^^^^^^^^
// 5
memset(bar, 0, sizeof(struct bar));
// ^^^^^^^^^^^^^^^^^^
// 1
}
// (NB. Exact sizes may differ; 1 and 5 given as relative examples only)
The fact that this is all well-defined is one reason that you didn't get a warning. Still, I'd hope that an intelligent compiler would spot your code as a possible programmer mistake — rationalising about why some given implementation does or does not emit some given warning in some non-mandated case, though, is largely folly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With