In article <11**********************@z14g2000cwz.googlegroups .com>
Mukul Pandey <mu**********@gmail.com> quoted no context, and there
was no previous article on my news server, so I have no idea what
might have been in article
<11**********************@o13g2000cwo.googlegroups .com>, except that
obviously it must have something to do with structure members:
1. by saying,
char a:4;
you are not just allocating 4 bits, instead, you are requesting
for a bit-wise allocation. Suppose, you know that you have three
attributes, with known ranges, you could say,
struct bitwise_alloc
{
char a:4; (range 0 to 15)
char b:2; (range 0 to 3)
char c:1; (range 0 to 1)
char d:1;
};
The size would still be 1 byte (if padding is not there). No allocation
below 1 byte is possible (for an object/variable).
Portable C code can only use "int", "signed int", and "unsigned
int" as bitfield base types. The above often works anyway though,
and is correct as far as it goes. (Note also that in C a "byte"
is a CHAR_BIT-bits-long entity, even if CHAR_BIT is more than 8.
This potentially differs from the 8-bit "octet" that most people
mean when they say "byte".)
There is a large problem with using plain "char" as the bitfield
type, however: plain char may be, and often is, signed. The
"a" member of the struct above would then have a guaranteed
range of -7 to +7 (and a typical range of -8 to +7), rather than
0 to 15. Instead of using plain (possibly-signed) char, if you
need the range to go from 0 to 15, use "unsigned char". (It
may still not even compile, if the compiler does not support
"char" types for bitfield members.)
2. you could do this using the compiler directive (#pragma pack),
but then it might not be a generic implementation.
Indeed. Not only is "#pragma pack" nonstandard, but even those
compilers that do implement it, tend to implement it differently
-- for instance, GCC prefers the __attribute__ spelling. :-)
It is worth noting, however, that no matter whether you use "char"
bitfields, or "#pragma", or "__attribute__", you have thrown
portability entirely out the window. The only difference is
how far out the window it has gone (and whether it has rolled
across the field and into the stream and run out with the river
to the sea :-) ).
In the C code I have seen, people who do this are usually attempting
to match an internal data structure to some external data format
(a file format, or network-data-stream, or hardware register, or
similar). Usually it *can* be done. Often, however, it is a
mistake even to try. C is not Ada; C has no representation clauses.
Instead of trying to trick the compiler into matching up an
internal representation with an external one, the C programmer is
often better off writing several small functions whose entire
purpose is to *translate* between the internal format and the
external one.
For instance, suppose that, instead of the "bitwise_alloc"
structure above, the goal is to read four values from a stdio
"FILE" object, whose ranges are 0..15, 0..3, 0..1, and 0..1,
and which are stored in an 8-bit octet with the "d" value in
bit zero, the "c" value in bit 7, the "b" value in bits 5
and 6 in backwards bit order (i.e., bit 5 is the high bit and
bit 6 is the low bit), and the "a" value in bits 4, 3, 2, and
1 in forwards order. Suppose also that we have:
struct value {
unsigned char val_a; /* range 0..15 */
unsigned char val_b; /* range 0..3 */
unsigned char val_c; /* range 0..1 */
unsigned char val_d; /* range 0..1 */
};
as the internal representation. Then we just need the following
function to read the external format:
int get_value(FILE *stream, struct value *result) {
int c;
if ((c = getc(stream)) == EOF)
return ERROR;
/*
* Value A is stored in bits 4..1: shift to 3..0 and mask.
*/
result->val_a = (c >> 1) & 0xf; /* bits 4..1 */
/*
* Value B is stored in bits 5 (0x20) and 6 (0x40) but
* in backwards bit order. Move bit 6 to bit 0 (shift 6) and
* bit 5 to bit 1 (shift 4).
*/
result->val_b = ((c & 0x20) >> 4) | ((c & 0x40) >> 6);
/*
* Value C is bit 7 (0x80), and value D is bit 0 (0x1).
*/
result->val_c = (c & 0x80) >> 7;
result->val_d = c & 0x01;
return OK;
}
The function required to write the external format should now be
obvious (and is left as an exercise :-) ).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.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.