packed datastructure - how to define?

  • Thread starter =?ISO-8859-15?Q?J=FCrgen?= Hochwald
  • Start date
?

=?ISO-8859-15?Q?J=FCrgen?= Hochwald

Hi

Maybe this is a simple question, but I don't know how to solve.

Background: A weather station connected to the serial port sends data
packets. This data packets are containing variables fom one byte up to 4
byted in mixed order. Now I want to define a structure to overlay it with
UNION over the receive buffer for easily access to the single values in the
data packet.
The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

How can I define a variable, which uses exactly one byte ?


Here is a small text app:
------------------------------------------
#include <stdio.h>
#include <stdlib.h>

struct data {
int i;
char c;
int j;
};

union ovr {
struct data d;
char c[16];
};

int main(void) {
union ovr d;
int l;

for (l=0;l<16;l++)
d.c[l]=l;

printf("size=%d\n",sizeof(d));
printf("i=%X\n",d.d.i);
printf("c=%X\n",d.d.c);
printf("j=%X\n",d.d.j);
}
--------------------------------
and the output:
size=16
i=3020100
c=4
j=B0A0908

To overlay the data packet correct, j must be 8070605.
 
M

Michael Mair

Hi Juergen,

Jürgen Hochwald said:
Maybe this is a simple question, but I don't know how to solve.

Background: A weather station connected to the serial port sends data
packets. This data packets are containing variables fom one byte up to 4
byted in mixed order. Now I want to define a structure to overlay it with
UNION over the receive buffer for easily access to the single values in the
data packet.
The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

How can I define a variable, which uses exactly one byte ?


Here is a small text app:
------------------------------------------
#include <stdio.h>
#include <stdlib.h>

struct data {
int i;
char c;
int j;
};

union ovr {
struct data d;
char c[16];
};

int main(void) {
union ovr d;
int l;

for (l=0;l<16;l++)
d.c[l]=l;

printf("size=%d\n",sizeof(d));
printf("i=%X\n",d.d.i);
printf("c=%X\n",d.d.c);
printf("j=%X\n",d.d.j);
}
--------------------------------
and the output:
size=16
i=3020100
c=4
j=B0A0908

To overlay the data packet correct, j must be 8070605.

There are several issues here:
- If you want to access something bytewise, use unsigned char
- The size of a char/signed char/unsigned char _always_ is one
byte
- A byte is not necessarily eight bit but at least so much.
Check the symbolic constant CHAR_BIT from <limits.h> to find
out the exact ratio
If you have a C99 compiler with the integer types in <stdint.h>,
then you can use the type uint8_t. 8 Bits often are referred to
as "octet"
- sizeof(int)>=sizeof(unsigned char), so your assumptions about
a certain ratio may be wrong
- In a structure, there may be padding bytes between the members
if there are alignment requirements. If sizeof(int) > 1 and
ints have to be sizeof(int)-aligned (that is, their address
can be divided by sizeof(int) without remainder), then there
are probably sizeof(int)-1 padding bytes between the c and j
members of your structure.
As an aside: If you have larger structures then it makes sense
to put the variables with the largest type first and then go
down in size -- this often leads to smaller structures.
- The bytes of types with size >1 are not necessarily ordered as
you assume. Thus,
unsigned int i=1;
unsigned char lowestbyte=((unsigned char *)&i)[0];
may yield lowestbyte==1 or lowestbyte==0.

So, check the necessary size, use
union ovr {
struct data d;
unsigned char c[sizeof(struct data)];
};
or do not use a union at all but access the structure representation
directly, find out the byte order (or: rather use shifting and masking
instead of access by unsigned char for portable code), and so on.

BTW: The offsetof macro yields the offset in bytes of a member of
a structure with respect to the start of the structure.

The comp.lang.c FAQ addresses several of these issues in detail.
It has been posted here on November 1 and can also be found at
http://www.eskimo.com/~scs/C-faq/top.html
The ASCII version is up to date, unlike the HTML version.


HTH
Michael
 
D

Default User

=?ISO-8859-15?Q?J=FCrgen?= Hochwald wrote:

The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

No it doesn't, or it's not a C compiler. What makes you think it's
taking up more than one byte?



struct data {
int i;
char c;
int j;
};

union ovr {
struct data d;
char c[16];
};

int main(void) {
union ovr d;
int l;

for (l=0;l<16;l++)
d.c[l]=l;

printf("size=%d\n",sizeof(d));
printf("i=%X\n",d.d.i);
printf("c=%X\n",d.d.c);
printf("j=%X\n",d.d.j);
}
--------------------------------
and the output:
size=16
i=3020100
c=4
j=B0A0908


Ah, it isn't the data size that is the problem, it's struct alignment.

There is no way in ISO standard C to define packed structs. Your
implementation may provide a way.




Brian
 
A

Alan Balmer

Hi

Maybe this is a simple question, but I don't know how to solve.

Background: A weather station connected to the serial port sends data
packets. This data packets are containing variables fom one byte up to 4
byted in mixed order. Now I want to define a structure to overlay it with
UNION over the receive buffer for easily access to the single values in the
data packet.
The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

How can I define a variable, which uses exactly one byte ?

struct data {
int i;
char c;
int j;
};
You have the answer in your subject line, but data packing in
structures is implementation and platform dependent and off topic
here. Your compiler may have a switch or pragma to force the structure
to be packed. OTOH, your platform may not allow access of j on an odd
boundary. You might consider alternatives, such as defining an int and
copying bytes 5-8 into it. Not a robust, portable method, but it will
probably work.
 
A

Alan Balmer

=?ISO-8859-15?Q?J=FCrgen?= Hochwald wrote:

The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

No it doesn't, or it's not a C compiler. What makes you think it's
taking up more than one byte?
The byte in the structure may be (and obviously is, in this case)
padded to align the int on a particular boundary..
 
E

Eric Sosman

Jürgen Hochwald said:
Hi

Maybe this is a simple question, but I don't know how to solve.

Background: A weather station connected to the serial port sends data
packets. This data packets are containing variables fom one byte up to 4
byted in mixed order. Now I want to define a structure to overlay it with
UNION over the receive buffer for easily access to the single values in the
data packet.
The problem is, that I cannot defind a variable, which only reserves one
byte of memory. A simple 'char' or 'char[1]' eats 4 bytes and all following
variables are not matching.

How can I define a variable, which uses exactly one byte ?

This is Question 2.12 in the comp.lang.c Frequently
Asked Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/faq.html

Unfortunately, the methods mentioned in the answer are
not portable (and are described as such). If you want a
portable solution, you will have to abandon the attempt
to make your program's variables match the externally-
defined format. Instead, receive the data packets into
an array of `unsigned char' and then copy the appropriate
bytes into your program's struct.

At first this may seem terribly inefficient, but it
actually is not. Your C compiler may be able to squeeze
the holes out of a struct, but there will probably be a
time penalty for every access to an unaligned field. The
penalty may be small or large (or even huge, on some kinds
of hardware), so spending a few cycles to copy the data
into a properly-aligned struct can be worth while.

Also, the copying step gives you an opportunity to
resolve things like "endian-ness" issues. If the weather
station likes to send a four-byte integer's high-order
byte first but your computer prefers to start with the
low-order byte, you would need to fiddle with the data
anyhow in order to make sense of it.

All in all, the "extra" code to reconcile the internal
and external format is seldom wasteful and often useful.
 
D

Default User

Alan said:
On 3 Nov 2004 14:26:04 -0800, "Default User"

The byte in the structure may be (and obviously is, in this case)
padded to align the int on a particular boundary..


So, that doesn't have anything to do with the OP's contention that he
can't define a data type of size 1.

You also snipped my further remark, after he listed the struct size:
alignment.



Brian
 
A

Alan Balmer

So, that doesn't have anything to do with the OP's contention that he
can't define a data type of size 1.

That was not his contention, as was obvious in the context which you
snipped.
You also snipped my further remark, after he listed the struct size:

alignment.
And realizing that later, you didn't go back and edit your first
impulse?
 
D

Default User

Alan said:
I don't edit your writing unless you pay me to do so.

That's not what I said, was it? And you did edit my writing, snipping
out part of my message to make your point stronger.



Brian
 

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,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top