Structure Size and Padding Byte Questions

D

dashley

I have the following constructs:

typedef struct
{
unsigned char a[3];
unsigned short b; //Presumed 16 bits
unsigned char crc;
} mystruct;

mystruct x;

....

x.crc = CalculateCrc8(&x, sizeof(x) - 1);
//Designed to exclude CRC from CRC calculation.

I'm not sure if the compiler is C90 or C99.

Questions:

a)I'm assuming that the compiler is free to insert a padding byte after x.a?

b)I'm assuming that if you obtain the memory for the structure as an automatic or via malloc(), the padding byte could have any value, and only a block memory operation such as memset() set it to 0?

c)Is the CRC calculation call -- especially the use of "sizeof() - 1" in this way -- valid on all platforms? Specifically, can the compiler insert structure padding bytes AFTER x.crc so that subtracting 1 from sizeof() won'thave the desired effect of excluding the CRC itself from the CRC calculation?

Thanks for any information, especially about what is guaranteed behavior and not guaranteed behavior.
 
B

Ben Bacarisse

I have the following constructs:

typedef struct
{
unsigned char a[3];
unsigned short b; //Presumed 16 bits
unsigned char crc;
} mystruct;

mystruct x;

...

x.crc = CalculateCrc8(&x, sizeof(x) - 1);
//Designed to exclude CRC from CRC calculation.

I'm not sure if the compiler is C90 or C99.

Questions:

a)I'm assuming that the compiler is free to insert a padding byte
after x.a?

Yes, and after b and crc as well.
b)I'm assuming that if you obtain the memory for the structure as an
automatic or via malloc(), the padding byte could have any value, and
only a block memory operation such as memset() set it to 0?

The padding can have any value with other allocations as well. What's
more it can acquire any value due valid operations on members of the
struct. For example, setting x.b = 1 could alter any or all of the
padding bytes.
c)Is the CRC calculation call -- especially the use of "sizeof() - 1"
in this way -- valid on all platforms?

No, it looks highly suspect to me on any platform. It might break from
one compiler version to another.
 
E

Eric Sosman

I have the following constructs:

typedef struct
{
unsigned char a[3];
unsigned short b; //Presumed 16 bits
unsigned char crc;
} mystruct;

mystruct x;

...

x.crc = CalculateCrc8(&x, sizeof(x) - 1);
//Designed to exclude CRC from CRC calculation.

I'm not sure if the compiler is C90 or C99.

Questions:

a)I'm assuming that the compiler is free to insert a padding byte after x.a?

Yes. Also after x.b (although that's unlikely) and after x.crc
(more likely than not). The only place where there definitely won't
be a padding byte is *before* x.a.
b)I'm assuming that if you obtain the memory for the structure as an automatic or via malloc(), the padding byte could have any value, and only a block memory operation such as memset() set it to 0?

Yes. Even if you memset() the entire struct to zero (or any
other value), padding bytes are not guaranteed to retain that value
when other operations are performed on the struct. Store something
in a a struct element, and padding bytes may change "spontaneously."
Assign one struct to another, and the padding bytes of the destination
need not match those of the source.
c)Is the CRC calculation call -- especially the use of "sizeof() - 1" in this way -- valid on all platforms? Specifically, can the compiler insert structure padding bytes AFTER x.crc so that subtracting 1 from sizeof() won't have the desired effect of excluding the CRC itself from the CRC calculation?

It's (potentially) invalid, because as you suspect the compiler
may insert padding after x.crc. Instead, you could use

#include <stddef.h>
...
x.crc = CalculateCrc8(&x, offsetof(mystruct, crc));

.... but you'd still have all the problems associated with any padding
prior to the crc element.
Thanks for any information, especially about what is guaranteed behavior and not guaranteed behavior.

There are few guarantees about padding bytes. They *have*
values, and you can observe (and change) them by treating the
struct as an array of char. However, operations on the struct's
"payload" elements are not guaranteed to leave the padding bytes
intact.

The usual reason for CRC's and so on is to improve detection
of transcription errors: When you send data from one system to
another, or when you store it in a file and read it back again,
you'd like to use a CRC to increase your confidence that the data
hasn't been mangled somewhere along the line. Therefore, you
usually want to calculate a CRC not for the struct your program
uses to manipulate the data, but for the byte stream that encodes
the data for reading and writing. If you write this way:

Copy the "payload" data from the struct to an array
of bytes,
Calculate and append a CRC or other checksum,
Write the entire blob

.... and read this way:

Read the blob into an array of bytes,
Calculate and verify the CRC or checksum,
Extract the data into a struct for the program's use

.... then you won't have to worry about padding and such. (This
also gives you a convenient hook for dealing with representation
issues, like endianness mismatches.)
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top