By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,710 Members | 1,605 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,710 IT Pros & Developers. It's quick & easy.

replace bitfields with shifts and masks

P: n/a
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
Jun 4 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
In article <NP******************************@t-one.net>,
Dave <da***@wmol.com> wrote:
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.
--
There are some ideas so wrong that only a very intelligent person
could believe in them. -- George Orwell
Jun 4 '06 #2

P: n/a
Walter Roberson wrote:
In article <NP******************************@t-one.net>,
Dave <da***@wmol.com> wrote:
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.


Doh, I forgot ntohl() :P

Thanks
Jun 4 '06 #3

P: n/a
>In article <NP******************************@t-one.net>,
Dave <da***@wmol.com> wrote:
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;
};
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.
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.


In article <e5**********@canopus.cc.umanitoba.ca>
Walter Roberson <ro******@ibd.nrc-cnrc.gc.ca> wrote: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.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Jun 4 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.