memset() on a struct or union


M

Mark

Hello,

having hard time to understand the way memset() works. Does the Standard
(I'm interested in both C90 and C99) guarantee that the function will set to
0 all the bits of the structure's members ?

Does the memset() act differently if a structure integrates unions ?

Quoting ISO C99: "The memset function copies the value of c (converted to an
unsigned char) into each of the first n characters of the object pointed to
by s.", but as I understand this rule does not apply if the object is, say,
an array of 'ints' with sizeof(int) > 1. Perhaps I don't get it right at
all.

Thanks.
 
Ad

Advertisements

I

Ian Collins

Mark said:
Hello,

having hard time to understand the way memset() works. Does the Standard
(I'm interested in both C90 and C99) guarantee that the function will
set to 0 all the bits of the structure's members ?

memset treats its argument as a bucket of bytes, it is not aware of the
type (hence the use of a void*.
Does the memset() act differently if a structure integrates unions ?
No.

Quoting ISO C99: "The memset function copies the value of c (converted
to an unsigned char) into each of the first n characters of the object
pointed to by s.", but as I understand this rule does not apply if the
object is, say, an array of 'ints' with sizeof(int) > 1. Perhaps I don't
get it right at all.

You have to specify the size of the object in bytes. For example if you
have an array of ints someSize long:

memset( yourArray, 0, someSize*sizeof(int) );
 
A

achp

having hard time to understand the way memset() works. Does the Standard
(I'm interested in both C90 and C99) guarantee that the function will set to
0 all the bits of the structure's members ?

The memset function knows nothing about your structures and its
members, it simply sets all the bytes in a given "range" to a given
value. If the value is 0, and the "range" covers some object of a
struct type, then yes, all the bits of the structure's members will be
set to 0.

However, this doesn't mean the structure's members themselves will be
set to 0. The standard requires that all integral-typed objects having
all their bits set to 0 are themselves equal to 0, but the
representation of pointers and floating-point is unspecified, and
therefore - at least theoretically - having all their bits set to 0 is
not necessarily equivalent to having themselves equal to 0.

For example:

struct X
{
char a;
int b;
double c;
void* d;
} x;

memset(&x, 0, sizeof x);
printf("%d %d %f %d", x.a, x.b, x.c, x.d != NULL);

This will print two zeroes for x.a and x.b and two more values for x.c
and x.d which are most likely zeroes on mainstream platforms but not
necessarily. To be pedantic, the code above has undefined behaviour
because access to the values of x.c and x.d which at the point of
access are not properly initialized. However, on mainstream platforms
this will work perfectly OK.
Does the memset() act differently if a structure integrates unions ?

C has no reflection, so memset knows nothing about structures and
unions. All it knows about is memory which is made up by a sequence of
bytes.

struct X
{
char a;
union
{
int b;
double c;
void* d;
};
} x;

memset(&x, 0, sizeof x);
printf("%d %d %f %d", x.a, x.b, x.c, x.d != NULL);

This code will yield the same output as above (and all the
reservations are valid as well). Members x.b, x.c and x.d are
overlapping in the memory this time; but the bytes allocated to them
are still all zeroes.
Quoting ISO C99: "The memset function copies the value of c (converted to an
unsigned char) into each of the first n characters of the object pointed to
by s.", but as I understand this rule does not apply if the object is, say,
an array of 'ints' with sizeof(int) > 1. Perhaps I don't get it right at
all.

Why not? Arrays are placed in the memory contiguously, therefore you
can use memset to initialize arrays as well.

int i, x[100];

memset(&x, 0, sizeof x);
for (i = 0; i < 100; ++i) printf("%d ", x);

This yields 100 zeroes. Assume, for example, that sizeof (int) == 4.
400 bytes are allocated for the array x. memset sets these 400 (sizeof
x) bytes to 0. Access to any x retrives corresponding 4 bytes out
of those 400, and those 4 bytes are all 0, making up the int value of
0.
 
M

Mark

Ian Collins said:
You have to specify the size of the object in bytes. For example if you
have an array of ints someSize long:

memset( yourArray, 0, someSize*sizeof(int) );

This is from the thread named "Initialising an array".
Eric Sosman said:
Also you can try the standard function memset:

int par[MAX];
memset(par, INT_MAX, MAX);
... except that this will only work if sizeof(int) == 1.
Even if you change the third argument to sizeof(int) * MAX
(or to sizeof par), this can work for only a few of the
possible values one might want in an int, and only then by
lucky (unlucky?) chance.

Doesn't this mean that "memset( yourArray, 0, someSize*sizeof(int) )" isn't
always guaranteed to zero up all the bits? Perhaps I misunderstood Mr.
Sosman's comment.
 
S

Seebs

having hard time to understand the way memset() works. Does the Standard
(I'm interested in both C90 and C99) guarantee that the function will set to
0 all the bits of the structure's members ?

Well, if used with a 0, yes.
Quoting ISO C99: "The memset function copies the value of c (converted to an
unsigned char) into each of the first n characters of the object pointed to
by s.", but as I understand this rule does not apply if the object is, say,
an array of 'ints' with sizeof(int) > 1. Perhaps I don't get it right at
all.

Sure it does. It's just that there's not necessarily a guarantee that
all-bits-zero will be a useful state for an object other than an unsigned
char.

-s
 
S

Seebs

This is from the thread named "Initialising an array".
Eric Sosman said:
Also you can try the standard function memset:

int par[MAX];
memset(par, INT_MAX, MAX);
... except that this will only work if sizeof(int) == 1.
Even if you change the third argument to sizeof(int) * MAX
(or to sizeof par), this can work for only a few of the
possible values one might want in an int, and only then by
lucky (unlucky?) chance.

Doesn't this mean that "memset( yourArray, 0, someSize*sizeof(int) )" isn't
always guaranteed to zero up all the bits? Perhaps I misunderstood Mr.
Sosman's comment.

The difference is that INT_MAX is probably not expressable in an unsigned
char (unless sizeof(int) is 1), but 0 is.

Here's the thing. Let's say you're on a 32-bit twos complement
system, with 8-bit chars.

int i;
memset(&i, INT_MAX, sizeof(int));

What does this do? Well, it computes the value of INT_MAX, which is
0x7fffffff, then converts that to unsigned char, yielding 0xff, then sets
each byte of i to 0xff, yielding 0xffffffff. Which is not the same as
0x7fffffff. Similarly:
int i[MAX];
memset(i, 0, MAX);
will set the first MAX bytes -- but i[MAX] is sizeof(int)*MAX bytes in
length, so it won't affect the whole array unless sizeof(int) == 1.

memset just treats everything as a bag of bytes. It has no way of knowing
whether the things you're pointing it at are something else, so it doesn't
care.

-s
 
Ad

Advertisements

A

achp

   int par[MAX];
   memset(par, INT_MAX, MAX);

     ... except that this will only work if sizeof(int) == 1.
Even if you change the third argument to sizeof(int) * MAX
(or to sizeof par), this can work for only a few of the
possible values one might want in an int, and only then by
lucky (unlucky?) chance.

Doesn't this mean that  "memset( yourArray, 0, someSize*sizeof(int) )" isn't
always guaranteed to zero up all the bits? Perhaps I misunderstood Mr.
Sosman's comment.

"memset( yourArray, 0, someSize*sizeof(int) )" shall always zero up
all the bits.

memset casts its second argument to unsigned char internally. Casting
zero always yields zero because it is a value which is for sure
representable in all integral types. Casting INT_MAX to unsigned char
is different, unsigned char simply cannot represent INT_MAX unless
sizeof (int) == 1. On a typical platform where sizeof (int) == 4,
INT_MAX is 0x7FFFFFFF, and (unsigned char)INT_MAX is 0xFF.
 
P

Peter Nilsson

Seebs said:
...It's just that there's not necessarily a guarantee that
all-bits-zero will be a useful state for an object other
than an unsigned char.

....than an integer type.

C90 implicitly guaranteed it for all integers, C99 (as of
one of the TCs) explicitly guarantees it.

N1256, 6.2.6.2p5: "...For any integer type, the object
representation where all the bits are zero shall be a
representation of the value zero in that type."
 
S

Seebs

C90 implicitly guaranteed it for all integers, C99 (as of
one of the TCs) explicitly guarantees it.

Oooh, shiny. And very handy.

Well, that was the last thing stopping ME from taking over the world.
When I crush nations under my feet, I shall remember you fondly.

-s
 
E

Eric Sosman

Oooh, shiny. And very handy.

Well, that was the last thing stopping ME from taking over the world.
When I crush nations under my feet, I shall remember you fondly.

Please refrain from using outmoded, idiosyncratic and
purely local terms in describing your forthcoming conquest.
The accepted International Standard language would be "When
I crush nations under my meters ..."
 
R

Richard Tobin

Eric Sosman said:
Please refrain from using outmoded, idiosyncratic and
purely local terms in describing your forthcoming conquest.
The accepted International Standard language would be "When
I crush nations under my meters ..."

Surely the International Standard spelling is "metres".

-- Richard
 
Ad

Advertisements

E

Eric Sosman

Ian Collins said:
You have to specify the size of the object in bytes. For example if
you have an array of ints someSize long:

memset( yourArray, 0, someSize*sizeof(int) );

This is from the thread named "Initialising an array".
Eric Sosman said:
Also you can try the standard function memset:

int par[MAX];
memset(par, INT_MAX, MAX);
... except that this will only work if sizeof(int) == 1.
Even if you change the third argument to sizeof(int) * MAX
(or to sizeof par), this can work for only a few of the
possible values one might want in an int, and only then by
lucky (unlucky?) chance.

Doesn't this mean that "memset( yourArray, 0, someSize*sizeof(int) )"
isn't always guaranteed to zero up all the bits? Perhaps I misunderstood
Mr. Sosman's comment.

With memset() you can fill a region of memory with all
zeroes, or with all ones, or with copies of any single byte
value. (Whether these are meaningful for the data objects
contained in that region is another matter.) What you can't
do is fill a region with a pattern of non-identical bytes.
In the other thread, the question was about setting all the
elements of an int[] to the value INT_MAX, and my point was
that INT_MAX very likely involves non-identical bytes: some
mixture of 0x7F and 0xFF is quite common, and may even be
universal.

If you want to fill a region with a "patterned" value, you
may be interested in this function I wrote long ago:


#include <string.h>

void
fillmem(void *pdest, size_t sdest, const void *pfrom, size_t sfrom)
/*
* Fills the `sdest' bytes starting at `pdest' with copies of the
*`sfrom' bytes starting at `pfrom'. The final copy will be partial
* if `sfrom' does not divide `sdest'.
*/
{
if (sdest > sfrom) {
/* Put one copy of the source pattern at the start of
* the destination.
*/
memcpy (pdest, pfrom, sfrom);
pfrom = pdest;
pdest = (char*)pdest + sfrom;
sdest -= sfrom;

/* Copy data from the beginning of the destination to the
* end, with each iteration doubling the amount copied.
*/
while (sdest > sfrom) {
memcpy (pdest, pfrom, sfrom);
pdest = (char*)pdest + sfrom;
sdest -= sfrom;
sfrom += sfrom;
}
}

/* Fill the final (or only) piece of the destination.
*/
memcpy (pdest, pfrom, sdest);
}

The loop looks like it could be a cache-killer, but I haven't
seen evidence of bad behavior on the machines where I've used it.
YMMV, the Secretary will disclaim, etc., etc.
 
R

Richard Tobin

Nobody said:
British spelling: "metre"
US spelling: "yard"

A metre is about 11/10 of a yard. Apparently Napoleon was a Spinal
Tap fan, and wanted his metres to go to 11.

-- Richard
 
B

bartc

Joe Wright said:
I believe you'll find the international spelling to be "meter" except
perhaps in Paris. And we know the French can't spell. Chien Chaud indeed.

A meter is what you have under the stairs.

A metre is 1000/25.4 inches.
 
N

Nick

Joe Wright said:
Look up "metre" in any dictionary you have to hand. You will be
referred to "meter" is every case. Even La Rousse.

By co-incidence I had Chamber's dictionary sitting such that I could
pick it up without moving in or from my seat. That's about as "to hand"
as you could get.

So I looked up "metre". Here's the first couple of lines of the entries
(with some adaptation for ASCII only):

"*metre*(1) or (US) *meter* [pronunciation] /n/ the regulated succession
of groups of syllables ...."

"*metre*(2) or (US) *meter* [pronunciation] /n/ the fundamental unit of
length in the metric system ...

It appears that you're wrong.

Just to really confirm this, there are two entries for "meter". The
first is "a measurer, an apparatus for measuring" and the second I quote
in it's entirety:

"*Meter*(2) US spelling of *metre*(1,2)
 
Ad

Advertisements

N

Nick Keighley

bartc said:
Joe Wright said:
Richard Tobin wrote:
Look up "metre" in any dictionary you have to hand. You will be referred to
"meter" is every case. Even La Rousse.

wikipedia have this to say "Two spellings of the name of the unit are
common in English: metre is preferred among the majority of countries
in the English-speaking world except in the United States, where the
spelling is meter"
 
N

Nick Keighley

British spelling: "metre"
US spelling: "yard"

I'm not happy about the adoption of the yard. Rods, Poles and Perch
are good enough for anyone!

God used the cubit why should we use anything else?
 
Ad

Advertisements

S

santosh

bartc said:
A meter is what you have under the stairs.

A metre is 1000/25.4 inches.

Yep. Metre is the spelling used in Commonwealth countries, but I'm
familiar with both to the point that I sometimes interchange between
them when writing; a bad habit I know.
 

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

Top