Bit Fields

Chris Torek chris at mimsy.umd.edu
Sun Nov 12 15:05:01 AEST 1989


In article <89111105491001 at masnet.uucp> mark.longo at canremote.uucp
(MARK LONGO) writes:
>  What I want to do is translate this HEX value into BINARY so I can
>check what `each bit' means....  For example:  6030h = 0110000000110000
>in base 2 ... Position 5: indicates `clear to send' ...
>
> Now ALL I need to do is somehow convert this 6030h number into BITS
>because EVERY position is important to me.

It is not clear to me what you *really* want to do.  Values stored in
a typical modern computer *are* in bits, no matter how they are written
when communicating with a person.

If you want to read and write binary values in C, you have to write your
own formatting and scanning functions, such as:

	/*
	 * Convert a value to nbits bits into a buffer of at least nbits+1
	 * characters.  Return the beginning of the buffer.
	 */
	char *btostr(char *buf, int nbits, long int value) {
		unsigned long int t = value;

		if (nbits <= 0)
			panic("invalid call to btostr");
		buf += nbits;	/* bits generated backwards */
		*buf = 0;
		do {
			*--buf = (t & 1) + '0';
			t >>= 1;	/* unsigned shift */
		} while (--nbits > 0);
		return (buf);
	}

	/* strtob is left to the reader */
	/* (hint: it can be done with strtol or strtoul) */

You can then write, e.g.,

	char bitbuf[13];
	printf("1234 = 0b%s\n", btostr(bitbuf, 12, 1234L));

If, instead, you want to test individual bits, you have a number of
different options, including bitfield structures.  I do not recommend
bitfield structures, as they tend to (a) tickle compiler bugs, (b)
produce poor (large and/or slow) code once these bugs are worked around,
and (c) be nonportable since two different compilers for the same
machine will produce different bit orders.

>It would be nice if i could do something like:
>   struct modem {
>	unsigned clear_to_send : 1;
>	unsigned data_set_ready: 1;
>	    .
>	    .
>	unsigned time_out :1;
>   } code;
>then put the 6030h into base 2 and throw it into code . Can it be done?

If you are determined to use bitfields despite my dire predictions ( :-) )
above:

	union foo {
		struct modem {
			<bits>
		};
		short	sixteen_bits;
	} code;
	code.sixteen_bits = 0x6030;

I find the simplest thing is to use `#define's for each bit group:

	#define	FOO_CTS	0x0001	/* clear to send */
	#define	FOO_DSR	0x0002	/* data set ready */
		...
	#define	FOO_TO	0x8000	/* timeout */

And:

	#define	FOO_BITS \
	"\020TO\017...\002DSR\001CTS"

and a `printf-like' function that prints a bit-value using the above:

	/* s points to FOO_BITS; b = value to print */
	any = 0;
	while ((i = *s++) != 0) {
		if (b & (1 << (i-1))) {
			(void) putchar(any ? ',' : '<');
			any = 1;
			for (; (c = *s) > 32; s++)
				(void) putchar(c);
		} else
			for (; *s > 32; s++)
				/* void */;
	}
	if (!any)
		(void) putchar('<');
	(void) putchar('>');

(Note that the above assumes ASCII coding or similar, such that
none of the letters to be printed with each bit have codes <= 32.
It also means at most 32 bits can be examined in this way.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list