EvilTeach
EvilTeach

Reputation: 28837

Someone is using the struct name as a variable name too. What does the code really say?

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?

Upvotes: 11

Views: 1728

Answers (5)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

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.

Upvotes: 2

CB Bailey
CB Bailey

Reputation: 791729

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.

Upvotes: 14

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

With the exception of run-time sized cases, the typical idiomatic way to use memset (as well as memcpy, malloc, etc.) is to do

memset(dst_ptr, 0, sizeof *dst_ptr);

or, equivalently,

memset(&dst_object, 0, sizeof dst_object);

Which is how it should have been used in this case as well

memset(&fred, 0, sizeof fred);

and the problem with the name conflict would not arise. The memset(fred, 0, sizeof fred) variant will work as well.

Upvotes: 0

Jerry Coffin
Jerry Coffin

Reputation: 490108

When you define the variable, it hides the name of the type, so yes, when you do sizeof(fred), you're getting the size of the array, not the size of the struct. it's pretty easy to verify this by simply printing out sizeof(fred).

The short answer, however, is just: "don't do that."

Upvotes: 1

martiert
martiert

Reputation: 1686

Shouldn't this be sizeof(fred)*(MAX_SIZE+1) since your array is MAX_SIZE+1 long?

Upvotes: 2

Related Questions