Clearing Padding in Structure

M

Martin

Is clearing a structure the following way well defined in C89? The
structure ACTION contains no floating point or pointer members. Only
integral types. My thoughts concern the padding - can and should it be
altered?

typedef unsigned char Byte;
#define MAX_ACTIONS 10

/* ... */

void clear_actions(ACTION *acts)
{
Byte *pByte = (Byte *)acts;
Byte *limit;

limit = pByte + sizeof(ACTION) * MAX_ACTIONS; /* 1 beyond array */

for ( ; pByte < limit; pByte++)
*pByte = 0;

} /* clear_actions */
 
U

user923005

Is clearing a structure the following way well defined in C89? The  
structure ACTION contains no floating point or pointer members. Only  
integral types. My thoughts concern the padding - can and should it be  
altered?

    typedef   unsigned char   Byte;
    #define   MAX_ACTIONS     10

    /* ... */

    void clear_actions(ACTION *acts)
    {
       Byte *pByte = (Byte *)acts;
       Byte *limit;

       limit = pByte + sizeof(ACTION) * MAX_ACTIONS; /* 1 beyond array */

       for ( ; pByte < limit; pByte++)
          *pByte = 0;

    } /* clear_actions */

I do not think that clearing the padding can be more dangerous than
not clearing it.

I guess that your function is exactly equivalent to:
memset(&mystruct, 0, sizeof mystruct);

I think that the definition of clearing objects with 0 bytes is only
clearly defined for char.

However, it will probably work on most real systems.

If you want to be fully portable, assign {0} to the struct instance on
declaration and it has to properly initialize all members (including
floating point and pointers). Or you can keep one of these laying
around:

static const struct mystruct gmystruct_zero_initializer = {0};

and use that subsequently to initialize things.

The only direct caveat I can find in the C99 standard is the footnote:

252) Note that this need not be the same as the representation of
floating-point zero or a null pointer constant.

for the calloc() function. I do seem to recall that there could be
some conceivable problem for some signed integer format from
discussions here of long ago, but I can't recall the particulars.
 
B

Ben Bacarisse

I guess that your function is exactly equivalent to:
memset(&mystruct, 0, sizeof mystruct);

I think that the definition of clearing objects with 0 bytes is only
clearly defined for char.

I think the assurance is extended for all integer types, signed and
unsigned.
 
R

Richard Heathfield

Ben Bacarisse said:
I think the assurance is extended for all integer types, signed and
unsigned.

It is. This has come up several times in the past few years, and on each
occasion nobody can remember the reference, let alone find it, but
generally somebody from ISO pops up to say "yes, sure, fine, no problem
for ints". No doubt something of the kind will happen again. (I think the
assurance is safely buried in a TC, BICBW.)
 
P

Peter Nilsson

Martin said:
Is clearing a structure the following way well defined
in C89? The structure ACTION contains no floating point
or pointer members.

What about aggregates thereof?
Only integral types. My thoughts concern the padding -
can and should it be altered?

You are right to be concerned, but in this specific case,
all bits zero must represent zero for all integral types
in both C90 and C99.
    typedef   unsigned char   Byte;
    #define   MAX_ACTIONS     10

    /* ... */

    void clear_actions(ACTION *acts)
    {
       Byte *pByte = (Byte *)acts;
       Byte *limit;

       limit = pByte + sizeof(ACTION) * MAX_ACTIONS;
/* 1 beyond array */

       for ( ; pByte < limit; pByte++)
          *pByte = 0;

    } /* clear_actions */

This can be simplified to a single memset(acts, 0, ...).

But if you want robustness against one day having float or
pointer types, then you can do something like...

void clear_actions(ACTION act[], size_t N)
{
static const ACTION zero;
size_t i;
for (i = 0; i < N; i++)
act = zero;
}
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:


It is. This has come up several times in the past few years, and on each
occasion nobody can remember the reference, let alone find it, but
generally somebody from ISO pops up to say "yes, sure, fine, no problem
for ints". No doubt something of the kind will happen again. (I think the
assurance is safely buried in a TC, BICBW.)

While we wait (for I can't remember the formal document that included
it) I'll just cite N1256.pdf:

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

This is marked with change bars in n1256, so it was not explicitly
there in the published standard.
 
K

Keith Thompson

Peter Nilsson said:
You are right to be concerned, but in this specific case,
all bits zero must represent zero for all integral types
in both C90 and C99.
[...]

Neither C90 nor C99 makes that guarantee explicitly. Such a guarantee
was added later in one of the post C99 Technical Corrigenda.

However, I don't believe there's ever been a C implementation on which
all-bits-zero was not a valid representation of 0 for all integral
types, and it's not unreasonable to rely on this.

(By contrast, there is no such guarantee for pointers or
floating-point types, and code that depends on such an assumption is
potentially non-portable.)
 
M

Martin

What about aggregates thereof?

The structure contains, in order, an 8-bit char, two sixteen-bit unsigned
ints, and an 8-bit char. No aggregates.
You are right to be concerned [about padding], but in thisspecific case,
all bits zero must represent zero for all
integral types in both C90 and C99.

True, but what about the padding areas?

This can be simplified to a single memset(acts, 0, ...).

But if you want robustness against one day having float or
pointer types, then you can do something like...

void clear_actions(ACTION act[], size_t N)
{
static const ACTION zero;
size_t i;
for (i = 0; i < N; i++)
act = zero;
}


I like that, thanks.
 
M

Martin

If you want to be fully portable, assign {0} to the struct instance on
declaration and it has to properly initialize all members (including
floating point and pointers). Or you can keep one of these laying
around:

static const struct mystruct gmystruct_zero_initializer = {0};

and use that subsequently to initialize things.

Thanks for that user923005, Peter Nilsson has provided a similar
suggestion.
 
M

Martin

I guess that your function is exactly equivalent to:
memset(&mystruct, 0, sizeof mystruct);

Not quite, my function is looping through the address space occupied by an
array of structures of the same type, and clearing it byte by byte.
 
M

Martin

The structure contains, in order, an 8-bit char, two sixteen-bit
unsigned ints, and an 8-bit char. No aggregates.

Correction, 'char' should read 'unsigned char'.
 
S

santosh

Martin said:
Not quite, my function is looping through the address space occupied
by an array of structures of the same type, and clearing it byte by
byte.

Er, won't exactly the same be accomplished with memset, unless you need
to clear storage pointed to by any structure members? The call might
be:

memset(&arr_of_structs[0], 0, sizeof arr_of_structs);

assuming that the array is statically allocated.

For dynamic allocation the calloc function will automatically clear the
memory area for you.
 
M

Martin

Er, won't exactly the same be accomplished with memset, unless you need
to clear storage pointed to by any structure members? The call might
be:

memset(&arr_of_structs[0], 0, sizeof arr_of_structs);

I know, but I was commenting on the codeline user923005 posted which used
memset to clear only one structure.

assuming that the array is statically allocated.

For dynamic allocation the calloc function will automatically clear the
memory area for you.

My concern was about the validity of clearing out the padding areas of the
structures.
 
B

Ben Bacarisse

Martin said:
Er, won't exactly the same be accomplished with memset, unless you need
to clear storage pointed to by any structure members? The call might
be:

memset(&arr_of_structs[0], 0, sizeof arr_of_structs);

I know, but I was commenting on the codeline user923005 posted which
used memset to clear only one structure.

assuming that the array is statically allocated.

For dynamic allocation the calloc function will automatically clear the
memory area for you.

My concern was about the validity of clearing out the padding areas of
the structures.

You don't need to worry. If the memset is valid (i.e. there is a
modifiable object to set) then you can't generate any invalid values
(given that you have only integer-type members). The members will be
all zero-valued, and no structure value can be trap representation.
 
P

pete

Martin said:
What about aggregates thereof?

The structure contains, in order, an 8-bit char,
two sixteen-bit unsigned
ints, and an 8-bit char. No aggregates.
You are right to be concerned [about padding],
but in thisspecific case,
all bits zero must represent zero for all
integral types in both C90 and C99.

True, but what about the padding areas?

That's a very good question.
What about them?
Why are you clearing the structure?
This can be simplified to a single memset(acts, 0, ...).

But if you want robustness against one day having float or
pointer types, then you can do something like...

void clear_actions(ACTION act[], size_t N)
{
static const ACTION zero;
size_t i;
for (i = 0; i < N; i++)
act = zero;
}


I like that, thanks.


I like it too.
It doesn't have to be static either.
You could do
const ACTION zero = {0};
instead.
 
M

Martin

That's a very good question.
What about them?
Why are you clearing the structure?

The structures need to be cleared occasionally. Upthread you will see I
said:

"My concern was about the validity of clearing out the padding areas of
the structures."

My original post shows that the function clear_actions() walks through the
entire storage area of the array of structures and sets each byte to zero.
My question regarding the padding areas was referring to the validity of
changing those. The code posted by Peter Nilsson avoids that problem.
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top