padding in structs 
Author Message
 padding in structs

Hello,
just curious, and I would appreciate your comments:

In the following code I am trying to use the padding bytes in a
struct. -Not that I think this could be of any practical use, I am
just curious if the code violates anything the standard says.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>

int main(void)
{
    unsigned char tc = 0x3e;
    int i;
    unsigned char *cp;

    struct test_t
    {
        char c[10];
        double d;
    } *testStruct;
    testStruct = calloc(sizeof testStruct, 1);

    if(testStruct != NULL)
    {
        cp = (unsigned char *)testStruct;
        for (i = 0; i < sizeof *testStruct; i++)
        {
            cp[i] = tc;
            putchar(cp[i]);
        }
        putchar('\n');
/* I have set the whole struct to an unsigned char value, but don't
access a member yet */

        testStruct->d = 1.23456;
        printf("%f\n", testStruct->d);

/* now I have assigned a value to a member, and I start to fiddle
with the padding*/
        for(i = 10; i < offsetof(struct test_t, d); i++)
        {
            putchar(cp[i]);
            cp[i] = 0x41;
            putchar(cp[i]);
        }
        putchar('\n');

/* I believe it is guaranteed, that testStruct->d is still valid */
        printf("%f\n", testStruct->d);
        free(testStruct);
        return EXIT_SUCCESS;
    }
    return EXIT_FAILURE;

Quote:
}

TIA, HAND
--
Robert Stankowic

"The regular early morning yell of horror" - Douglas Adams


Tue, 12 Aug 2003 02:27:37 GMT  
 padding in structs

Quote:
>Hello,
>just curious, and I would appreciate your comments:

>In the following code I am trying to use the padding bytes in a
>struct. -Not that I think this could be of any practical use, I am
>just curious if the code violates anything the standard says.

D:\CLC\DEV_S\STANKOWI>bc proj.prj
1.234560

1.234560

D:\CLC\DEV_S\STANKOWI>rhide
This is RHIDE Version 1.4. Copyright (c) 1996,1997 by Robert H?hne
             (Sep 30 1997 23:06:59)

Quote:

1.234560
>A>A

1.234560
Exiting due to signal SIGSEGV
Page fault at eip=0000324a, error=0006
eax=fc8f3248 ebx=ff4e3594 ecx=ff4e35a4 edx=0000ea78 esi=ff4e35a4
edi=0000001e
ebp=00101fb0 esp=00101fa4 program=D:\CLC\DEV_S\STANKOWI\PROJ.EXE
cs: sel=01f7  base=832ac000  limit=ff4f2fff
ds: sel=01ff  base=832ac000  limit=ff4f2fff
es: sel=01ff  base=832ac000  limit=ff4f2fff
fs: sel=012f  base=0001df30  limit=0000ffff
gs: sel=020f  base=00000000  limit=0010ffff
ss: sel=01ff  base=832ac000  limit=ff4f2fff
App stack: [00102000..00082000]  Exceptn stack: [0000e9d8..0000ca98]

Call frame traceback EIPs:
  0x0000324a
  0x0000162d
  0x000029aa

Draw your conclusions.

Quote:
>#include <stdlib.h>
>#include <string.h>
>#include <stdio.h>
>#include <stddef.h>

>int main(void)
>{
>    unsigned char tc = 0x3e;
>    int i;
>    unsigned char *cp;

>    struct test_t
>    {
>        char c[10];
>        double d;
>    } *testStruct;
>    testStruct = calloc(sizeof testStruct, 1);

-[_]-------------------------------
Watch ------------------------------3-[ ]
 *testStruct,20m: 00 00 3E 3E 3E 3E 3E 3E 3E 3E 38 32 8F FC C1 C0 F3 3F 6F
6A

Maybe you want

    testStruct = calloc(sizeof *testStruct, 1);

-----------------------------------
Watch ------------------------------3-----
 *testStruct,20m: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6F
6A

Of course, you know that a double with all bits to 0 is not necessarely a
valid number.

Quote:
>    if(testStruct != NULL)
>    {
>        cp = (unsigned char *)testStruct;
>        for (i = 0; i < sizeof *testStruct; i++)
>        {
>            cp[i] = tc;
>            putchar(cp[i]);
>        }
>        putchar('\n');

-----------------------------------
Watch ------------------------------3-----
*testStruct,20m: 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 6F 6A

Ok, It is probably what you wanted.

Quote:
>/* I have set the whole struct to an unsigned char value, but don't
>access a member yet */

>        testStruct->d = 1.23456;
>        printf("%f\n", testStruct->d);

-----------------------------------
Watch ------------------------------3-----
*testStruct,20m: 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 38 32 8F FC C1 C0 F3 3F 6F 6A
                                               <----the double------->

Quote:
>/* now I have assigned a value to a member, and I start to fiddle
>with the padding*/
>        for(i = 10; i < offsetof(struct test_t, d); i++)

Why 10?

Quote:
>        {
>            putchar(cp[i]);
>            cp[i] = 0x41;
>            putchar(cp[i]);
>        }
>        putchar('\n');

No change!
-----------------------------------
Watch ------------------------------3-----
*testStruct,20m: 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 38 32 8F FC C1 C0 F3 3F 6F 6A

Quote:
>/* I believe it is guaranteed, that testStruct->d is still valid */
>        printf("%f\n", testStruct->d);
>        free(testStruct);
>        return EXIT_SUCCESS;
>    }
>    return EXIT_FAILURE;
>}

(The watch windows is for the Borland C implementation for Intel 16-bit)

--
-hs-    Tabs out, spaces in.
CLC-FAQ: http://www.eskimo.com/~scs/C-faq/top.html
ISO-C Library: http://www.dinkum.com/htm_cl
FAQ de FCLC : http://www.isty-info.uvsq.fr/~rumeau/fclc



Tue, 12 Aug 2003 05:52:51 GMT  
 padding in structs

Quote:

> Hello,
> just curious, and I would appreciate your comments:

> In the following code I am trying to use the padding bytes in a
> struct. -Not that I think this could be of any practical use, I am
> just curious if the code violates anything the standard says.

<code snipped>

AFAICT, your code actually appears to be valid.

C99, in 6.2.6.1:6, states:

 When a value is stored in an object of structure or union type,
 including in a member object, the bytes of the object representation
 that correspond to any padding bytes take unspecified values. The
 values of padding bytes shall not affect whether the value of such an
 object is a trap representation. Those bits of a structure or union
 object that are in the same byte as a bit-field member, but are not
 part of that member, shall similarly not affect whether the value of
 such an object is a trap representation.

So, if the object can not be made (or un-made)  to be a trap
representation (an object representation which doesn't represent a
value of the object type), explicitly setting the values of those
bytes would seem to be allowed.  The footnote to this paragraph in the
standard would seem to strengthen that interpretation:

 Thus, an automatic variable can be initialized to a trap
 representation without causing undefined behavior, but the value of
 the variable cannot be used until a proper value is stored in it.

Micah



Tue, 12 Aug 2003 06:50:09 GMT  
 padding in structs
-hs- schrieb:

Quote:


> >Hello,
> >just curious, and I would appreciate your comments:

> >In the following code I am trying to use the padding bytes in a
> >struct. -Not that I think this could be of any practical use, I am
> >just curious if the code violates anything the standard says.

> >    testStruct = calloc(sizeof testStruct, 1);

[....]

Quote:

> Maybe you want

>     testStruct = calloc(sizeof *testStruct, 1);

[....]
Uh, silly mistake, that :-(

Quote:

> Of course, you know that a double with all bits to 0 is not necessarely a
> valid number.

Yes, that is why I wrote "...but don't access a member yet" later

Quote:

> >    if(testStruct != NULL)
> >    {
> >        cp = (unsigned char *)testStruct;
> >        for (i = 0; i < sizeof *testStruct; i++)
> >        {
> >            cp[i] = tc;
> >            putchar(cp[i]);
> >        }
> >        putchar('\n');

> -----------------------------------
> Watch ------------------------------3-----
> *testStruct,20m: 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 3E 6F 6A

> Ok, It is probably what you wanted.

Yes, and I think it is valid C up to now (besides the silly mistake
in calloc())

Quote:

> >/* I have set the whole struct to an unsigned char value, but don't
> >access a member yet */

> >        testStruct->d = 1.23456;
> >        printf("%f\n", testStruct->d);

[....]

Quote:

> >/* now I have assigned a value to a member, and I start to fiddle
> >with the padding*/
> >        for(i = 10; i < offsetof(struct test_t, d); i++)

> Why 10?

10 is the first position after the char array - your compiler did
not insert padding here, so the for loop is never executed (mine
inserts 6 bytes). I was curious, if it is allowed to use the padding
_if_ a compiler inserts them and with the for() condition I wanted
to make sure only the paddindg bytes are accessed

[....]

Thank you for your comments
Kind regards

--
Robert Stankowic

"The regular early morning yell of horror" - Douglas Adams



Tue, 12 Aug 2003 13:48:26 GMT  
 padding in structs
Micah Cowan schrieb:

Quote:


> > Hello,
> > just curious, and I would appreciate your comments:

> > In the following code I am trying to use the padding bytes in a
> > struct. -Not that I think this could be of any practical use, I am
> > just curious if the code violates anything the standard says.

> <code snipped>

> AFAICT, your code actually appears to be valid.

..besides my silly mistake in the calloc() statement, as -hs-
pointed out

Quote:

> C99, in 6.2.6.1:6, states:

>  When a value is stored in an object of structure or union type,
>  including in a member object, the bytes of the object representation
>  that correspond to any padding bytes take unspecified values. The
>  values of padding bytes shall not affect whether the value of such an
>  object is a trap representation. Those bits of a structure or union
>  object that are in the same byte as a bit-field member, but are not
>  part of that member, shall similarly not affect whether the value of
>  such an object is a trap representation.

> So, if the object can not be made (or un-made)  to be a trap
> representation (an object representation which doesn't represent a
> value of the object type), explicitly setting the values of those
> bytes would seem to be allowed.  The footnote to this paragraph in the
> standard would seem to strengthen that interpretation:

>  Thus, an automatic variable can be initialized to a trap
>  representation without causing undefined behavior, but the value of
>  the variable cannot be used until a proper value is stored in it.

> Micah

That was what I had in mind. Furthermore footnote 38 in that
paragraph says:

Thus, for example, structure assignment may be implemented
element-at-a-time or via memcpy

Thank you for taking the time to respond
Kind regards

--
Robert Stankowic

"The regular early morning yell of horror" - Douglas Adams



Tue, 12 Aug 2003 13:57:21 GMT  
 padding in structs

in comp.lang.c:

Quote:

> > Hello,
> > just curious, and I would appreciate your comments:

> > In the following code I am trying to use the padding bytes in a
> > struct. -Not that I think this could be of any practical use, I am
> > just curious if the code violates anything the standard says.

> <code snipped>

> AFAICT, your code actually appears to be valid.

> C99, in 6.2.6.1:6, states:

>  When a value is stored in an object of structure or union type,
>  including in a member object, the bytes of the object representation
>  that correspond to any padding bytes take unspecified values. The
>  values of padding bytes shall not affect whether the value of such an
>  object is a trap representation. Those bits of a structure or union
>  object that are in the same byte as a bit-field member, but are not
>  part of that member, shall similarly not affect whether the value of
>  such an object is a trap representation.

> So, if the object can not be made (or un-made)  to be a trap
> representation (an object representation which doesn't represent a
> value of the object type), explicitly setting the values of those
> bytes would seem to be allowed.  The footnote to this paragraph in the
> standard would seem to strengthen that interpretation:

>  Thus, an automatic variable can be initialized to a trap
>  representation without causing undefined behavior, but the value of
>  the variable cannot be used until a proper value is stored in it.

> Micah

I disagree with your conclusion, although I agree that the standard
might appear ambiguous in that I can't find a reference either way.

The fact that padding bytes take "unspecified values" does not mean
that any arbitrary values are acceptable.  In the context of the
standard, "unspecified behavior" is something an implementation
chooses to do that it is not required to document.  That does not mean
that it is unimportant or arbitrary.

It is quite possible that in accessing such a structure all bytes,
including padding bytes, are physically read on the bus, and there is
no guarantee that some overall checking is performed that might fail
with the implementation's original padding bytes replaced by arbitrary
values.

--
Jack Klein
Home: http://JK-Technology.Com



Wed, 13 Aug 2003 12:23:58 GMT  
 padding in structs
Jack Klein schrieb:

Quote:


> in comp.lang.c:


> > > Hello,
> > > just curious, and I would appreciate your comments:

> > > In the following code I am trying to use the padding bytes in a
> > > struct. -Not that I think this could be of any practical use, I am
> > > just curious if the code violates anything the standard says.

> > <code snipped>

> > AFAICT, your code actually appears to be valid.

> > C99, in 6.2.6.1:6, states:

> >  When a value is stored in an object of structure or union type,
> >  including in a member object, the bytes of the object representation
> >  that correspond to any padding bytes take unspecified values. The
> >  values of padding bytes shall not affect whether the value of such an
> >  object is a trap representation. Those bits of a structure or union
> >  object that are in the same byte as a bit-field member, but are not
> >  part of that member, shall similarly not affect whether the value of
> >  such an object is a trap representation.

> > So, if the object can not be made (or un-made)  to be a trap
> > representation (an object representation which doesn't represent a
> > value of the object type), explicitly setting the values of those
> > bytes would seem to be allowed.  The footnote to this paragraph in the
> > standard would seem to strengthen that interpretation:

> >  Thus, an automatic variable can be initialized to a trap
> >  representation without causing undefined behavior, but the value of
> >  the variable cannot be used until a proper value is stored in it.

> > Micah

> I disagree with your conclusion, although I agree that the standard
> might appear ambiguous in that I can't find a reference either way.

> The fact that padding bytes take "unspecified values" does not mean
> that any arbitrary values are acceptable.  In the context of the
> standard, "unspecified behavior" is something an implementation
> chooses to do that it is not required to document.  That does not mean
> that it is unimportant or arbitrary.

> It is quite possible that in accessing such a structure all bytes,
> including padding bytes, are physically read on the bus, and there is
> no guarantee that some overall checking is performed that might fail
> with the implementation's original padding bytes replaced by arbitrary
> values.

> --
> Jack Klein
> Home: http://JK-Technology.Com

Jack,
the following paragraphs, as I understand (and I may be wrong)
exclude all unsigned char operations on objects of any type from
undefined/unspecified behaviour:

6.2.6 Representations of types
6.2.6.1 General

3 Values stored in objects of type unsigned char shall be
represented using a pure
binary notation.36)
4 Values stored in objects of any other object type consist of n *
CHAR_BIT bits, where n
is the size of an object of that type, in bytes. The value may be
copied into an object of
type unsigned char [n] (e.g., by memcpy); the resulting set of bytes
is called the
object representation of the value. Two values (other than NaNs)
with the same object
representation compare equal, but values that compare equal may have
different object
representations.
5 Certain object representations need not represent a value of the
object type. If the stored
value of an object has such a representation and is accessed by an
lvalue expression that
does not have character type, the behavior is undefined. If such a
representation is
produced by a side effect that modifies all or any part of the
object by an lvalue
expression that does not have character type, the behavior is
undefined.37) Such a
representation is called a trap representation.
36) A positional representation for integers that uses the binary
digits 0 and 1, in which the values
represented by successive bits are additive, begin with 1, and are
multiplied by successive integral
powers of 2, except perhaps the bit with the highest position.
(Adapted from the American National
Dictionary for Information Processing Systems.) A byte contains
CHAR_BIT bits, and the values of
type unsigned char range from 0 to 2 CHAR_BIT
- 1.
37) Thus, an automatic variable can be initialized to a trap
representation without causing undefined
behavior, but the value of the variable cannot be used until a
proper value is stored in it.

And from 6.2.6.1
(#--> highlights by me)
6 When a value is stored in an object of structure or union type,
including in a member
object, the bytes of the object representation that correspond to
any padding bytes take
unspecified values.38) #--> The values of padding bytes shall not
affect whether the value of
such an object is a trap representation. Those bits of a structure
or union object that are
in the same byte as a bit-field member, but are not part of that
member, shall similarly not
affect whether the value of such an object is a trap representation.
7 When a value is stored in a member of an object of union type, the
bytes of the object
representation that do not correspond to that member but do
correspond to other members
take unspecified values, but the value of the union object #-->
shall not thereby become a trap
representation.
8 Where an operator is applied to a value which has more than one
object representation,
which object representation is used shall not affect the value of
the result. Where a value
is stored in an object using a type that has more than one object
representation for that
value, it is unspecified which representation is used, #--> but a
trap representation shall not be
generated.

If I don't misunderstand this paragraphs

struct test
{
   char c[10];
   double d;

Quote:
} *p_test;

unsigned char *p_char;
double d_v;
char c_v[10];

p_test = malloc(sizeof *p_test);
if(p_test != NULL)
{
   p_char = (unsigned char *)p_test;
/*use the memory as array of unsigned char..
(malloc() returns a pointer sufficiently aligned for any type of
object)
now I am done with that*/
   p_test->d = some_valid_double_value;
   strcpy(p_test->c, "abcdefghi");
/*strcpy is supposed to stop copying when it detects the '\0', and I
don't think the assignment of the double is allowed to access
storage outside of the n bytes forming p_test->d. (would'nt that be
disastrous in an implementation with no padding ?) As I understand
the same applies for
accessing the now properly initialized members - which is the only
allowed way to work with the struct besides memcpy()ing the whole
struct, which is explicitely allowed.*/
   d_v = p_test->d;
   strcpy(c_v, p_test->c);
   free(p_test);

Quote:
}

The question actually comes out as:
Am I allowed to
malloc some space
properly initialize and use it as one type
properly initialize and use it as a different type
free it

or do I have to free() and malloc() it inbetween ?

--
Robert Stankowic

"The regular early morning yell of horror" - Douglas Adams



Wed, 13 Aug 2003 16:03:10 GMT  
 padding in structs

Quote:

> I disagree with your conclusion, although I agree that the standard
> might appear ambiguous in that I can't find a reference either way.

> The fact that padding bytes take "unspecified values" does not mean
> that any arbitrary values are acceptable.  In the context of the
> standard, "unspecified behavior" is something an implementation
> chooses to do that it is not required to document.  That does not mean
> that it is unimportant or arbitrary.

That is absolutely correct, and I took that into consideration.
However, the fact that the standard requires these bytes to /not/
affect the trap representation status of the object is what led me to
this conclusion.

Quote:

> It is quite possible that in accessing such a structure all bytes,
> including padding bytes, are physically read on the bus, and there is
> no guarantee that some overall checking is performed that might fail
> with the implementation's original padding bytes replaced by arbitrary
> values.

That is /precisely/ what is guaranteed by the standard when it says
that these padding bytes may not be used to affect whether the
object is a trap representation.

However, I'm not much more comfortable with my conclusion than you
are, and in truth am kind of hoping someone can prove me wrong (or at
least that I'm not necessarily right) :)

One thing that I /would/ deduce from the language that says the
padding bytes take "unspecified values" is that, while the other
langauge concerning trap representation may restrain the padding bytes
from affecting the object, that doesn't mean that those padding bytes
will keep the values you assigned to them when you read from them.

At any rate, if anyone were to actually write such code as this in
earnest, I'm afraid I'd have to go grab a couple of buddies from
c.l.c., pay them a visit, and beat the living *crap* out of them ;)

Micah



Thu, 14 Aug 2003 04:46:28 GMT  
 padding in structs

Quote:

>Hello,
>just curious, and I would appreciate your comments:

>In the following code I am trying to use the padding bytes in a
>struct. -Not that I think this could be of any practical use, I am
>just curious if the code violates anything the standard says.

I don't think it directly violates the Standard, but it is quite
certainly extremely non-portable and absolutely not guaranteed to
work at all. The compiler writer might have had the same idea :-)

Quote:
>#include <stdlib.h>
>#include <string.h>

Why? Where are you using <string.h>?

Quote:
>#include <stdio.h>
>#include <stddef.h>

>int main(void)
>{
>    unsigned char tc = 0x3e;
>    int i;
>    unsigned char *cp;

>    struct test_t
>    {
>        char c[10];
>        double d;
>    } *testStruct;
>    testStruct = calloc(sizeof testStruct, 1);

You don't need calloc() here. Plain malloc() is enough, since you
are overwriting the memory area immediately anyway.

Quote:
>    if(testStruct != NULL)
>    {
>        cp = (unsigned char *)testStruct;
>        for (i = 0; i < sizeof *testStruct; i++)
>        {
>            cp[i] = tc;
>            putchar(cp[i]);

Taking an assumption that 'tc' (0x3e) is a printable character.

Quote:
>        }
>        putchar('\n');
>/* I have set the whole struct to an unsigned char value, but don't
>access a member yet */

This should be fine, if I understand it correctly. Even if an array
of sizeof(double) 0x3es were a trap value for double. But I admit
walking on a thin ice here.

Quote:
>        testStruct->d = 1.23456;
>        printf("%f\n", testStruct->d);

>/* now I have assigned a value to a member, and I start to fiddle
>with the padding*/
>        for(i = 10; i < offsetof(struct test_t, d); i++)
>        {
>            putchar(cp[i]);
>            cp[i] = 0x41;
>            putchar(cp[i]);

Taking an assumption that 0x41 is a printable character.

Quote:
>        }
>        putchar('\n');

>/* I believe it is guaranteed, that testStruct->d is still valid */

<AOL> Me too. </AOL>

Quote:
>        printf("%f\n", testStruct->d);

However, I am not sure if the padding bytes haven't changed by this
time. Anyone?

Quote:
>        free(testStruct);
>        return EXIT_SUCCESS;
>    }
>    return EXIT_FAILURE;
>}

>TIA, HAND

--
Peter Pichler (Increment my "From:" address if your email bounces.)


Tue, 19 Aug 2003 20:33:46 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. Padding in structs

2. padding a struct to a defined size

3. padding in structs..

4. padding in a statically initialized struct

5. struct padding and sizeof

6. sizeof(struct) and padding

7. Q: howto prevent struct padding

8. create a padded struct?

9. C++ 5.0 and sizeof (struct) / padding ?

10. preventing struct padding

11. Padding to mulitple-of-8-bytes: too much padding added

12. ? pad spare ?

 

 
Powered by phpBB® Forum Software