replace bitfields with shifts and masks

D

Dave

I need to rewrite the following using shifts and masks for portability
sakes, and to get rid of the BYTE_ORDER issue.

/* CODE */
struct test {
#if BYTE_ORDER == BIG_ENDIAN
unsigned char ver:4;
unsigned char res1:4;
#else
unsigned char res1:4;
unsigned char ver:4;
#endif
unsigned char reserved2;
unsigned short checksum;
};

void
function(unsigned char *data)
{
struct test *t = (struct test *)data;

if (t.ver == 1) {
/* match */
}
}

/* END */

I was thinking I could just do the following, but it does not seem to work.

void
function(unsigned char *data)
{
uint32_t test = *(uint32_t *)data;

/* shift 28 bits, mask 4 */
if (((test >> 28) & 0x0f) == 1) {
/* match */
}
}

I am thinking the declaration is not correct.
Thanks for any help

- Dave
 
W

Walter Roberson

I need to rewrite the following using shifts and masks for portability
sakes, and to get rid of the BYTE_ORDER issue.
/* CODE */
struct test {
#if BYTE_ORDER == BIG_ENDIAN
unsigned char ver:4;
unsigned char res1:4;
#else
unsigned char res1:4;
unsigned char ver:4;
#endif
unsigned char reserved2;
unsigned short checksum;
};
void
function(unsigned char *data)
{
struct test *t = (struct test *)data;

if (t.ver == 1) {
/* match */
}
}

/* END */
I was thinking I could just do the following, but it does not seem to work.
void
function(unsigned char *data)
{
uint32_t test = *(uint32_t *)data;
/* shift 28 bits, mask 4 */
if (((test >> 28) & 0x0f) == 1) {
/* match */
}
}
I am thinking the declaration is not correct.

I'm not surprised it didn't work. You've made an improper
assumption that just because a byte occurs first in a structure,
that the byte will be the Most Significant Byte when the
structure is reinterpreted as an integer value. That assumption
mostly works out on strict big-endian machines, but it rarely
works out on little-endian machines.

What you need to know is that when a CPU loads several bytes
of memory to become a numeric value, that the byte order in
memory may well be not be the order the bytes will appear in the
numeric value. For example, if memory happens to have consequative
bytes 1 2 3 4, then when that block of bytes is loaded as an integer
value, the CPU register may hold 2 1 4 3 or 4 3 2 1 or any of
several other possible orders. Numeric value order is not certain
to be the same as the order written to memory. (This is not
a problem for the CPU because the scrambling/descrabling algorithm
is -consistant-.)

It is not sufficient to know that the machine is "big endian" or
"little endian", as there are 24 possible orders that can be used
to store 4 bytes. Two of those orders are in very common use,
but at least one other of them is common enough that it likely
will be encountered by a program that is intended to be portable.

There are easy run-time tests to determine what the byte
ordering is, and easy reordering routines.
 
D

Dave

Walter said:
I'm not surprised it didn't work. You've made an improper
assumption that just because a byte occurs first in a structure,
that the byte will be the Most Significant Byte when the
structure is reinterpreted as an integer value. That assumption
mostly works out on strict big-endian machines, but it rarely
works out on little-endian machines.

What you need to know is that when a CPU loads several bytes
of memory to become a numeric value, that the byte order in
memory may well be not be the order the bytes will appear in the
numeric value. For example, if memory happens to have consequative
bytes 1 2 3 4, then when that block of bytes is loaded as an integer
value, the CPU register may hold 2 1 4 3 or 4 3 2 1 or any of
several other possible orders. Numeric value order is not certain
to be the same as the order written to memory. (This is not
a problem for the CPU because the scrambling/descrabling algorithm
is -consistant-.)

It is not sufficient to know that the machine is "big endian" or
"little endian", as there are 24 possible orders that can be used
to store 4 bytes. Two of those orders are in very common use,
but at least one other of them is common enough that it likely
will be encountered by a program that is intended to be portable.

There are easy run-time tests to determine what the byte
ordering is, and easy reordering routines.

Doh, I forgot ntohl() :p

Thanks
 
C

Chris Torek

This is apparently an attempt to "fake up" a representation clause
for something that, in C, is best described as:

unsigned char buf[4];

(but note that the "checksum" is now in individual "C byte" pieces
rather than one probably-larger unit; now *you* control the order
of the pieces, instead of letting the compiler do it, much as you
now control the order of the bitfields within the first "C byte").

If your target machine has greater-than-8-bit "C bytes" ("char"s),
you may still have some problems, but they are problems you were
going to have no matter what.

It is not sufficient to know that the machine is "big endian" or
"little endian", as there are 24 possible orders that can be used
to store 4 bytes. Two of those orders are in very common use,
but at least one other of them is common enough that it likely
will be encountered by a program that is intended to be portable.

Or, more simply, treat the array of bytes as an array of bytes.
Stop giving up control of the layout. Extract byte #0 and shift
and mask as needed:

if (((data[0] >> 4) & 0x0f) == 1) {
...
}

(If you deal with the individual bytes of data as individual bytes
of data, you never need tricks like "htonl" either.)
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top