"memset" vs "= {0}"...Are they equivalent if your initializing variables?

N

Nollie

Say you have a struct:

struct MYSTRUCT
{
int x;
int y;
int w;
int h;
};

and you want to declare an instance of that struct and initialize it
to zero. Is "memset" necessary or can i simply initially set it equal
to {0}.

Is this:
MYSTRUCT myStruct = {0};

the same as this:
MYSTRUCT myStruct;
memset(&myStruct, 0, sizeof(MYSTRUCT));

?

The first way seems faster, but I see alot of people doing it the
second way. Could someone please shed some light on the subject?
TIA.
 
J

John Harrison

Say you have a struct:

struct MYSTRUCT
{
int x;
int y;
int w;
int h;
};

and you want to declare an instance of that struct and initialize it
to zero. Is "memset" necessary or can i simply initially set it equal
to {0}.

Is this:
MYSTRUCT myStruct = {0};

the same as this:
MYSTRUCT myStruct;
memset(&myStruct, 0, sizeof(MYSTRUCT));

?

The first way seems faster,

Why do you say it 'seems faster'? The only way to tell if it is faster is to
time it (or if you are very knowledgable look at the generated machine
code). Remeber compilers are usually pretty code at optimising code, I would
certainly hope that the two methods would be exactly the same on a good
compiler (but I haven't actually checked this).
but I see alot of people doing it the
second way. Could someone please shed some light on the subject?

The two ways are the same for the struct you have declared. But if you had a
struct with members that had a constructor (e.g. a std::string) then memset
would be wrong. So that is the advantage of the second method, it works in
more situations and you could reasonable hope to get a compiler error
message if you used it incorrectly.

john
 
T

Tom Widmer

Say you have a struct:

struct MYSTRUCT
{
int x;
int y;
int w;
int h;
};

and you want to declare an instance of that struct and initialize it
to zero. Is "memset" necessary or can i simply initially set it equal
to {0}.

Is this:
MYSTRUCT myStruct = {0};

the same as this:
MYSTRUCT myStruct;
memset(&myStruct, 0, sizeof(MYSTRUCT));

?

The first way seems faster, but I see alot of people doing it the
second way. Could someone please shed some light on the subject?

The first way is generally better, since it zero initializes all
members. Memsetting to 0 is not always the same as zero initializing,
particularly for floating point and pointer members, which may have 0
values that aren't all bits zero.

Performance wise, I don't know which would be faster, you'd have to
measure it.

Tom
 
J

John Harrison

would be wrong. So that is the advantage of the second method, it works in

I meant first method.

john
 
J

JKop

struct MYSTRUCT
{
int x;
int y;
int w;
int h;
};
MYSTRUCT myStruct = {0};

All this does is set "myStruct.x" to 0, all the others
still contain no particular value.

MYSTRUCT myStruct;
memset(&myStruct, 0, sizeof(MYSTRUCT));

This is the Microsoft way of doing things.

In fact, they've even made a... uh... macro... out of it
called "ZeroMemory" which you use like so:

ZeroMemory(&myStruct, sizeof(MYSTRUCT));

Don't use the Microsoft way. It's non-portable, plus it
screws things up when you have the likes of:

struct Blah
{
int k;
std::string p;
};

Instead, do the following:

struct Blah
{
int x;
int y;
int w;
int h;
std::string r;
};

Blah poo = Blah();

This gives all member variables their default value, which
for the intrinsic types is 0, for pointer is the null
pointer value which may or may not be represented by 0
(memset is unaware of this and as such can screw things
up), and for classes it calls their default constructor
with no arguments.


Blah poo = Blah();

is superiour in every way and is fully portable. Use it!


-JKop
 
R

Ron Natalie

JKop said:
All this does is set "myStruct.x" to 0, all the others
still contain no particular value.

Wrong answer....When you omit terms in an aggregate initializer the rest
are default initialized.
Instead, do the following:

struct Blah
{
int x;
int y;
int w;
int h;
std::string r;
};

Blah poo = Blah();
So would
Blah poo = { 0 };
 
T

Tom Widmer

All this does is set "myStruct.x" to 0, all the others
still contain no particular value.

Nope, remaining members are value-initialized, which for built-ins
means initialized to 0. You can also do:

MYSTRUCT myStruct = {};

to get the same effect.

Tom
 
J

JKop

MYSTRUCT myStruct = {};


Cool! Didn't know that.

The only advantage

MYSTRUCT myStruct = MYSTRUCT();

would have over it thought is that it can be used for *any*
type, as opposed to just for arrays and POD's. My proposal
would be especially preferable for use in a template.

-JKop
 
N

Nollie

struct Blah
{
int x;
int y;
int w;
int h;
std::string r;
};

Blah poo = Blah();

This gives all member variables their default value, which
for the intrinsic types is 0, for pointer is the null
pointer value which may or may not be represented by 0
(memset is unaware of this and as such can screw things
up), and for classes it calls their default constructor
with no arguments.


Blah poo = Blah();

is superiour in every way and is fully portable. Use it!


-JKop

Not necessarily. Of the three methods I've tested, Blah()
appears to be the slowest.

The method:

Blah poo;
memset(&poo, 0, sizeof(Blah));

is the fastest, and

Blah poo = {0}

is a very close second;

Basically, you must compromise speed for safety and portability.

This is first time I've ever timed functions. I'm Visual Studio.NET
2003, SDK, WindowsXP.

My timing algorithm:
LARGE_INTEGER start;
LARGE_INTEGER end;
QueryPerformanceCounter( &start );
....Do Something
QueryPerformanceCounter( &end );
TRACE( TEXT( "Time = %d\n" ), end.QuadPart-start.QuadPart );

Granted, we're talking minimal differences, but that's besides the
point.

Please explain a little deeper as to why memset might not set a
pointer or a floating point number to zero. It does on my computer.

-Nollie
 
J

JKop

Not necessarily. Of the three methods I've tested, Blah()
appears to be the slowest.

The method:

Blah poo;
memset(&poo, 0, sizeof(Blah));

is the fastest, and

Blah poo = {0}

is a very close second;

Basically, you must compromise speed for safety and portability.

This is first time I've ever timed functions. I'm Visual Studio.NET
2003, SDK, WindowsXP.

My timing algorithm:
LARGE_INTEGER start;
LARGE_INTEGER end;
QueryPerformanceCounter( &start );
...Do Something
QueryPerformanceCounter( &end );
TRACE( TEXT( "Time = %d\n" ), end.QuadPart-start.QuadPart );

Granted, we're talking minimal differences, but that's besides the
point.

Please explain a little deeper as to why memset might not set a
pointer or a floating point number to zero. It does on my computer.

-Nollie

Sometimes it takes me 10mins 23secs to get to the bustop. Sometimes it takes
9mins 58secs...

I wouldn't use "QueryPerformanceCounter" as an indicator for this, unless
you time it a few thousand times and get the average, but even still, I'm
not sure how accurate it'd be.

As regards pointers... well let's say that on a certain system, a pointer
variable takes up 32 bits in memory, as so:


0000 0000 0000 0000 0000 0000 0000 0000


What you're looking at above is "all bits zero". On Windows, this indicates
that the pointer is a null pointer. Now imagine a system where the memory
address 0 is a valid one, ie. it's the first byte of memory, and that on
this particular system, the null pointer value is:

1111 1111 1111 1111 1111 1111 1111 1111


When you write a program with the following line in it:


int* p_k = 0;

The compiler doesn't produce code that sets all bits to zero... no no...
what it does is produce code that sets it to the null pointer value for that
system (and/or for that type, I believe systems may choose to have different
null pointer values depending on the type...). But "memset" doesn't have a
clue about this, all it does is set all bits to zero, which may be a valid
memory address on some systems, hence it's not portable.

And as regards floating point numbers, implementations aren't obligated to
represent the value zero as "all bits zero" either.

I don't see how either of the three could be slower/faster than each other,
they should all yield the same machine code (except maybe the call to
"memeset" might add overhead if it's not inline...)


-JKop
 
J

JKop

JKop posted:
Sometimes it takes me 10mins 23secs to get to the bustop. Sometimes it
takes 9mins 58secs...

I wouldn't use "QueryPerformanceCounter" as an indicator for this,
unless you time it a few thousand times and get the average, but even
still, I'm not sure how accurate it'd be.

As regards pointers... well let's say that on a certain system, a
pointer variable takes up 32 bits in memory, as so:


0000 0000 0000 0000 0000 0000 0000 0000


What you're looking at above is "all bits zero". On Windows, this
indicates that the pointer is a null pointer. Now imagine a system
where the memory address 0 is a valid one, ie. it's the first byte of
memory, and that on this particular system, the null pointer value is:

1111 1111 1111 1111 1111 1111 1111 1111


When you write a program with the following line in it:


int* p_k = 0;

The compiler doesn't produce code that sets all bits to zero... no
no... what it does is produce code that sets it to the null pointer
value for that system (and/or for that type, I believe systems may
choose to have different null pointer values depending on the type...).
But "memset" doesn't have a clue about this, all it does is set all
bits to zero, which may be a valid memory address on some systems,
hence it's not portable.

And as regards floating point numbers, implementations aren't obligated
to represent the value zero as "all bits zero" either.

I don't see how either of the three could be slower/faster than each
other, they should all yield the same machine code (except maybe the
call to "memeset" might add overhead if it's not inline...)


-JKop

And I hope you realize what havoc "memset" would cause with
a non-POD type...

-JKop
 
A

Andrew Koenig

All this does is set "myStruct.x" to 0, all the others
still contain no particular value.

I think not. If you brace-initialize any elements of an aggregate, the ones
you don't mention get set to zero.

So, for example:

int x[5] = { 42 };

and

int x[5] = { 42, 0, 0, 0, 0 };

are equivalent.
 
J

JKop

One thing I forgot to mention:

When you do "memset", padding bits (if any) get altered
too. I'm not sure if the Standard allows this...


-JKop
 
R

Ron Natalie

JKop said:
One thing I forgot to mention:

When you do "memset", padding bits (if any) get altered
too. I'm not sure if the Standard allows this...
Allows what? You are allowed to access them, yes their state
is undefined during normal assignment/initialization.
 
J

JKop

Ron Natalie posted:
Allows what? You are allowed to access them, yes their state
is undefined during normal assignment/initialization.

I'm not sure if the Standard allows you to access the
padding bits.

For instance, if you have:

struct Blah
{
int a;
char b;
char c;
char d;
int b;
};


Chances are that it will be lain out in memory as so:

| a | b | c | padding | d


You can access the object as follows:

poo.a
poo.b
poo.c
poo.d

And a copy constructor and a assignment operator will both
copy the four member variables, but I'm not sure if the
Standard gives us control over the padding bits... anyone
know? I recall looking in the Standard for this before and
finding nothing.

Let's say hypothetically speaking that you *can't* mess
with padding bits. A certain implementation, when you do
the following:

Blah poo;
char x;

Might stick "x" into memory as so:

| a | b | c | x | d |


Again, I stress *hypothetically speaking*.

So does anyone know if the Standard allows messing with
padding?


-JKop




-JKop
 
R

Ron Natalie

JKop said:
I'm not sure if the Standard allows you to access the
padding bits.

Read the last paragraph of 3.10 of the standard.
And a copy constructor and a assignment operator will both
copy the four member variables, but I'm not sure if the
Standard gives us control over the padding bits... anyone
know? I recall looking in the Standard for this before and
finding nothing.

The standard doesn't specify any behavior as to what happens to the
pad bytes in assignment or construction.
So does anyone know if the Standard allows messing with
padding?
If you mean aliasing it to char* and then accessing the chars, it is allowed.
 
J

JKop

I'm not sure if the Standard allows you to access the padding bits.
Read the last paragraph of 3.10 of the standard.

<QUOTE>
15 If a program attempts to access the stored value of an object through an
lvalue of other than one of the following
types the behavior is undefined48):
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic
type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified
version of the dynamic type of
the object,
— an aggregate or union type that includes one of the aforementioned types
among its members (including,
recursively, a member of a subaggregate or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic
type of the object,
— a char or unsigned char type.
</QUOTE>


Hmmm... I suppose.


Anyone?


-JKop
 
G

Greg Comeau

Please explain a little deeper as to why memset might not set a
pointer or a floating point number to zero. It does on my computer.

Because all bits zero is not a valid representation for
floating points or pointers on many platforms.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top