When shorts are longer than longs !

J

James Dow Allen

I've hardly ever used bitfields, but now have an
application where a union of different bitfielded
structures seems like the proper solution.

For example,
union {
struct {
unsigned long f1:9, f2:4, f3:5, f4:14;
} ua;
struct {
unsigned long f12:13, f3:5, f4:14;
} ub;
} uu;

(Let's be clear: portability is *NOT* my primary goal;
if/when portability is desired, 'make' would need to
run some endianness tests and generate appropriate
definitions for the usage of f12.)

Do other c.l.c'ers ever do something like the above?
Frankly, the bitfields have such annoyances (especially
endianness dependence) that I may end up "rolling my
own" bitfields, even though C's bitfields would enhance
readability and, perhaps, time efficiency.

I used a provocative Subject line to get attention!
On my Intel-linux-gcc laptop, sizeof(uu) is 4, but
if I replace the "long"s with "short"s then
sizeof(uu) is 6. I *do* understand why this is
(I think!) but still found it amusing enough to report.

James Dow Allen
 
J

James Kuyper

James said:
I've hardly ever used bitfields, but now have an
application where a union of different bitfielded
structures seems like the proper solution.

For example,
union {
struct {
unsigned long f1:9, f2:4, f3:5, f4:14;
} ua;
struct {
unsigned long f12:13, f3:5, f4:14;
} ub;
} uu;

(Let's be clear: portability is *NOT* my primary goal;

That's good, because using 'long' for a bitfield is not portable.
if/when portability is desired, 'make' would need to
run some endianness tests and generate appropriate
definitions for the usage of f12.)

Do other c.l.c'ers ever do something like the above?

Not that I can remember. Bit-fields are useful mainly for saving space
in a structure, but they're practically useless in portable code for
describing the layout of external data. Virtually everything that takes
up a lot of space in my programs is buffers for storing data that either
comes from outside the program, or will be written outside of it, so the
space that would be saved by storing any of the other data in bitfields
would be negligible in comparison. Since there's generally a time
overhead associated with extracting bitfields, it's usually not worth it.
For external data, I use unsigned char, masking and bit-shifts to
implement the functional equivalent of bit-fields.
Frankly, the bitfields have such annoyances (especially
endianness dependence) that I may end up "rolling my
own" bitfields, even though C's bitfields would enhance
readability and, perhaps, time efficiency.

I agree about the readability, but I wouldn't expect the time efficiency
to be great; ultimately the compiler will be performing the same shift
and mask operations, either way.
 
I

Ian Collins

James said:
I've hardly ever used bitfields, but now have an
application where a union of different bitfielded
structures seems like the proper solution.

For example,
union {
struct {
unsigned long f1:9, f2:4, f3:5, f4:14;
} ua;
struct {
unsigned long f12:13, f3:5, f4:14;
} ub;
} uu;

(Let's be clear: portability is *NOT* my primary goal;
if/when portability is desired, 'make' would need to
run some endianness tests and generate appropriate
definitions for the usage of f12.)

Do other c.l.c'ers ever do something like the above?
Frankly, the bitfields have such annoyances (especially
endianness dependence) that I may end up "rolling my
own" bitfields, even though C's bitfields would enhance
readability and, perhaps, time efficiency.

I've used them often, mainly in drivers and protocols headers. In all
case and on all the compilers I've used, the generated code was as good
as had written bit masking and the code a lot clearer. Oh, all the
compilers used the same order as well.
 
B

Boon

Eric said:
IMHO, bit-fields are *not* of much use for mapping to
specified formats. You can pretty much always get them to
do what you want on compiler X, but then discover that the
X arrangement doesn't work on compiler Y. Shift-and-mask
has its problems, yes, but fewer of them.

Could you elaborate on the problems with the shift-and-mask strategy?
 
B

Ben Bacarisse

James Dow Allen said:
I've hardly ever used bitfields, but now have an
application where a union of different bitfielded
structures seems like the proper solution.
Do other c.l.c'ers ever do something like the above?

Not exactly like that no. I do like to use bit-fields when they
encode what I mean in a natural way. For example, I often have a
struct whose purpose is to store program options which will use
one-bit bit-fields for the flags (originally of type "unsigned" but
now I'd use "bool").
Frankly, the bitfields have such annoyances (especially
endianness dependence) that I may end up "rolling my
own" bitfields, even though C's bitfields would enhance
readability and, perhaps, time efficiency.

There are times when rolling you own has no advantage. For example,
if you want to pick apart a floating-point number you will have
something akin to endian issues if you use either bit-fields or
something like Richard Heathfield's example code. Is such a case, I'd
use a bit-field and accept that it has to change from one architecture
to another.

When the data has a well-defined endianness (e.g. external protocol
data) then rolling your own is a clear win.
 
B

Ben Bacarisse

Eric Sosman said:
Kenneth said:
[...]
Does ISO C now specify how bitfields are allocated within the data?
(Not that it matters to me, since the only things for which we use
bitfields are single-bit flags, and we just use #defines to define
bitmasks.)

There are some specifications, but they're pretty much worthless
when portability is a concern...

<snip good stuff, I'm really just piggybacking>

It is off-topic, I know, but given the pedigree of C only a little
off-topic.

I've always thought it a shame that C never got BCPL's SLCT and OF
operators. SLCT len:shift:eek:ffset creates a values that can be stored,
passed about etc, bit can then be used to access and/or set the
designated sub-portion of a word (BCPL is typeless) using the OF
operator.

A C version would, I think, be even more useful that the BCPL one
since the type of what would be the pointer argument to OF could be
used to make it more flexible. Maybe it should be proposed! :)
 
A

Antoninus Twink

I *never* use bitfields.

You also *never* use long long, *never* use VLAs, *never* use //
comments, etc.

What relevance do your personal prejudices have to pragmatic people who
don't have your autistic hang-ups?
 
A

Antoninus Twink

Size: C's integers (all flavors) have implementation- defined
sizes, so the number of bits in a `long', say, may be different on
machines X and Y. If an externally- imposed format requires a 48-bit
field you might fit it comfortably in machine X's 64-bit `long', but
the same code wouldn't work with machine Y's 32-bit `long'.

Come on Eric, leave this nonsense about rejecting C99 to Heathfield.

It's been over 10 years since the C standard introduced many flavors of
fixed-width type: uint64_t, int_fast8_t, int_least32_t, and so on ad
nauseam.
There's also the possibility of padding bits, but that seems to be a
theoretical concern.

When did that ever put you off? Purely theoretical concerns are the
stock in trade of the clc regulars.
 
J

jameskuyper

Kenneth said:
James Kuyper wrote: .... ....
I gave up on bitfields for permanent storage long ago, instead using ....
Does ISO C now specify how bitfields are allocated within the data?

It imposes some limitations, but not many. 6.7.2.1 says
 
J

James Dow Allen

Some of the repetitive rejoinders and surrejoinders
in these threads could be eliminated if we gave each
other a little more credit. :)

My actual code involves a union of several different
bitfielded structures, with field names somewhat more
descriptive than in OP. (We're constantly reminded to
demonstrate a point with *minimal* examples, and then
criticized for the minimality! :)
In the example, I'm not at all
sure why you didn't use "unsigned int" -- except, perhaps,
to prove that portability isn't your primary goal ;-)

The actual code uses Uint32. Reread the Subject line
to learn why I (whimsically) changed this to unsigned long.
     Bit-fields *are* convenient if you need to cram several
independent small quantities into a single struct and then
create a very large number of struct instances.  That is,
they should be viewed as space-savers, not as format-matchers.

FWIW, this is *exactly* what I'm doing. The application is
specifically to build a type of very large table in minimal
memory.

Others quibbled with my mention of "time efficiency". It's
been decades since I compared specific architectures but
Sun's compiler for 68020-based machines certainly *did*
generate *significantly* faster code for C bitfields
compared with "hand-rolled" bitfields.

James Dow Allen
 
J

James Dow Allen

In the code I posted, a bitfielded slot
is exactly 32 bits. I have other, even more
space-efficient, routines, where slots are *not*
multiples of 8 bits. For these I do use
"hand-rolled" bitfield ops with macros similar in
function to those Mr. Heathfield posts.

/* This function gets the Indexth n-bit unsigned int
 * field from the bit array. To do this, it builds
 * the unsigned int value bit by bit.
 [snip] */
unsigned int Get_nBit_Int(unsigned char *BitArray,
                          unsigned int n,
                          unsigned int Index,
                          unsigned int BaseBit)
[snip]

I don't want to join the Heathfield bashing, but ...

bit-by-bit??? Heavens! Getting/setting n bits wholesale
is a bit(!) tricky, but uses far fewer lines of code
than your posted code. True, 99% of the time, speed will
be irrelevant, but I'd expect more perfectionism in proudly
posted code.

James
 
A

Antoninus Twink

bit-by-bit??? Heavens! Getting/setting n bits wholesale is a bit(!)
tricky, but uses far fewer lines of code than your posted code. True,
99% of the time, speed will be irrelevant, but I'd expect more
perfectionism in proudly posted code.

Heathfield is proud of it because he doesn't know any better. He has no
instinctive feeling for what's a good or a bad way to solve a particular
problem - his only interest is in producing a solution that generates no
warnings under gcc's most pedantic settings. Efficiency doesn't even
figure on his radar.

Let's not forget that this is the man who proudly boasts to have rolled
his own multiprecision integer library (because GMP isn't Strictly
Conforming 1990 ISO Standard C code) where the integers are stored and
manipulated as *strings*. It's beyond belief.
 
E

Eric Sosman

James said:
James said:
[... bit-fields in two structs in a union ...]

My actual code involves a union of several different
bitfielded structures, with field names somewhat more
descriptive than in OP. (We're constantly reminded to
demonstrate a point with *minimal* examples, and then
criticized for the minimality! :)

The trick is to trim to minimality, but not further.
The actual code uses Uint32. Reread the Subject line
to learn why I (whimsically) changed this to unsigned long.

Sorry; the Subject line doesn't lead me to the "Aha!"
moment. Sherlock Holmes studied a corpse and told the police
the height, nationality, social status, and facial complexion
of the other person who'd been present at the time of death;
I'm less skilled at deductions.
FWIW, this is *exactly* what I'm doing. The application is
specifically to build a type of very large table in minimal
memory.

Fine, but I don't see how I was supposed to deduce that
by staring at an isolated union definition -- a definition,
in fact, that gives the declared type no name or alias, and
thus could not have been used to build multiple instances of
the union object. Just from studying the definition, all I
can tell is that you're a left-handed violinist (or just
possibly a violist) of Polish-Dutch-Malay descent and fond
of herring in rice vinegar -- beyond that, nothing.
 
O

Old Wolf

I've hardly ever used bitfields, but now have an
application where a union of different bitfielded
structures seems like the proper solution.

I've found bitfields to be more trouble than
they are worth. Instead, I use bit-access
macros along the lines of what R Heathfield
posted. YMMV of course :)
 
J

James Dow Allen

James Dow Allen said:
<snip>
But if you feel like posting a better, faster version, fabulous! Do
it! That's precisely the kind of thing this group is for.

Okay, fair enough. Will be grateful for useful suggestions.
(On top of Google Groups's problems, I'm posting from
a misconfigured environment, so apologies in advance
if this message is hosed.)

/*
* Routines to read and write ("hand-rolled") bit-fields.
* I've made only minimal effort to time-optimize these
* routines: take up the challenge!
*
* While bitc > BITS_BG would clearly fail,
* bitc == BITS_BG is also forbidden.
* Easy fix for that would be to make B_One of larger
* type than Bgroup, e.g. (long long), but this might
* increase time in every case. Is there a better way?
*/

/* Next two normally arrive via #includes */
#define CHAR_BIT 8
typedef unsigned long Bgroup;

#define BITS_BG (CHAR_BIT * sizeof(Bgroup))
#define B_One ((Bgroup)1)

#define SJS0(p, k, v) \
(*(p) = *(p) & ((B_One << BITS_BG - (k)) - 1) \
| (v) << BITS_BG - (k))

#define SJS1(p, k, n, v) \
(*(p) = *(p) & (~((B_One << BITS_BG - (n)) \
- (B_One << BITS_BG - (n) - (k)))) \
| (v) << BITS_BG - (n) - (k))

/* set |bitc| bits to |datum|, offset |offs| bits from *|p| */
void setbits(Bgroup *p, int bitc, int offs, Bgroup datum)
{
int kn;

assert(0 < bitc && bitc < BITS_BG);
p += offs / BITS_BG;
offs %= BITS_BG;
if ((kn = bitc + offs) > BITS_BG) {
SJS1(p, BITS_BG - offs, offs, datum >> kn - BITS_BG);
SJS0(p + 1, kn - BITS_BG, datum);
} else if (offs) {
SJS1(p, bitc, offs, datum);
} else {
SJS0(p, bitc, datum);
}
}

/* return the |bitc| bits at offset |offs| bits from *|p| */
Bgroup getbits(Bgroup *p, int bitc, int offs)
{
int kn = bitc + offs % BITS_BG;

assert(0 < bitc && bitc < BITS_BG);
p += offs / BITS_BG;
return (kn > BITS_BG
? p[0] << kn - BITS_BG | p[1] >> BITS_BG + BITS_BG - kn
: p[0] >> BITS_BG - kn)
& (B_One << bitc) - 1;
}

James Dow Allen
 
J

James Dow Allen

     Sorry; the Subject line doesn't lead me to the "Aha!"
moment.

I just thought "When shorts are longer than longs" was slightly
entertaining. Rightfully, no one pursued this irrelevance.
     Bit-fields *are* convenient if
[used] as space-savers.
FWIW, this is *exactly* what I'm doing. . .
  Fine, but I don't see how I was supposed to deduce that

This may be an example of what I meant by giving each
other credit. I *should* have mentioned the space-saving
goal in OP, but unconsciously elided it, thinking it
to be obvious. :) :)
Just from studying the definition, all I
can tell is that you're a left-handed violinist (or just
possibly a violist) of Polish-Dutch-Malay descent and fond
of herring in rice vinegar -- beyond that, nothing.

Very close! But Scots is the largest ethnic contribution
which, as mentioned in earlier threads, might help account for
my irregular sense of whimsy. :)

James
 
I

Ian Collins

Richard said:
I *never* use bitfields. Let's qualify that. Firstly, I'm talking
only about C's built-in bitfields. Secondly, I'm excluding exegetic
uses. Thirdly, I'm excluding situations where I desire, or am
obliged, or find it convenient, to use other people's libraries
which incorporate bitfield usage. (I can't think of any examples of
that off-hand, but it's as well to exclude them anyway.)

So what do I do when I need to talk to bits? Easy - an array of
unsigned char, with macros. A few millennia ago I wrote a simple
set of functions to manage n-bit values, and it's quite easy to use
them to simulate bit-fields.

Why do some people get so hung up on bitfields? Everywhere I've used
used them, the alternative was ugly code.
 
B

BartC

I *never* use bitfields. Let's qualify that. Firstly, I'm talking
only about C's built-in bitfields.
So what do I do when I need to talk to bits? Easy - an array of
unsigned char, with macros. A few millennia ago I wrote a simple
set of functions to manage n-bit values, and it's quite easy to use
them to simulate bit-fields.

That's an excellent idea. Perhaps we can do away with structs too and just
use char arrays and a bunch of macros to Get/Set ints of various widths from
specific offsets in the array.

(In fact most features of C can be removed and the language would still be
viable. For example, you only really need a single char array variable per
scope (using casts to access individual variables), and of course all
control structures except goto. Functions I think are still needed (unless
gcc's label pointers are available). As I discovered when attempting to use
C as a target language from another.)
 
C

Chris Dollin

BartC said:
That's an excellent idea. Perhaps we can do away with structs too and just
use char arrays and a bunch of macros to Get/Set ints of various widths from
specific offsets in the array.

There are (at least) two uses of bitfields one might desire.

One is to clearly express the size (and hence value bounds) of small
integer members of a struct, and to allow such fields to be accessed
and updated in the same way as ordinary members, using dot-syntax.
The only problems (that I can think of) are that you can have pointers
to such fields and that the compiler is under no obligation to pack the
bit-fields "nicely" in the structure. In particular the most efficient
way of writing the fields for one compiler may be sub-optimal for a
different one, leaving you angsting if your code has to run on both.

The other use is to try and get the bits in a suitable position for
matching some existing layout, such as control bits for an IO register
or fields overlaid on a float. For this, C bitfields are pretty much
useless: the compiler freedoms referred to above mean that you /do not
know/ where the bitfields you write in your struct will end up (unless
you are committed to a very specific implementation that documents and
preserves that behaviour over updates). In this case, you are better off
with bit-twiddling operations, possibly disguised behind macros.

Finally note that all the bit-field members in the world won't help
much if you want to dynamically choose which bits you're updating.
 
G

Guest

Why do some people get so hung up on bitfields?  

because they have a list of portability problems as long as your
arm.
Everywhere I've used
used them, the alternative was ugly code.

I don't think the code is *that* ugly. Yes the macros/functions
that do the job look pretty nasty but the actual application
code fine to me.
 

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
474,434
Messages
2,571,685
Members
48,796
Latest member
Greg L.

Latest Threads

Top