[net.lang.c] enum, bit fields, cpp...

turner@ucbesvax.UUCP (02/01/84)

Perhaps there should also be a "bitsizeof" in addition to "sizeof".
Defining number of bits per byte (#define NBBY in some places) is
not good enough for machines whose byte does not evenly divide the bit-
length all scalar types.

Thus, with enum types cleaned up the way they ought to be (hope, pray)
one could say "bitsizeof (enum foo)" for various ultra-hacky purposes.
Even, I would hope,

    typedef enum { north, south, east, west } direction;

    struct {
	...
	bool flag: bitsizeof (bool);	/* (dumb, since always == 1) */
	direction dir: bitsizeof (direction);	/* pack next to flag */
	...

Hmmm, this seems fraught with terrors for compiler-writers, somehow.  Are
enums always int-sized (or better, rounded to short or char as appropriate)
when used alone?  In which case, are their bitsizeof's always that of the
primitive scalars they fit into?  Or should bitsizeof always mean "minimum
number of bits required to represent this scalar type?  That would at least
be consistent.  Having enums be always packed when they are members of
structures is also possible, but possibly confusing as well.

Or are there other solutions to this whole mess?
---
Michael Turner (ucbvax!ucbesvax.turner)

chris@umcp-cs.UUCP (02/27/84)

``lint'' will catch those ("warning: assignment to possibly sign
extended bitfield loses precision" or something like that).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris.umcp-cs@CSNet-Relay

ka@hou3c.UUCP (Kenneth Almquist) (02/27/84)

The ANSI committee will have to do something about bit fields.  Currently,
the way to store a boolean in a single bit of storage is to say

	struct { int flag: 1; } var;

and only test var.flag against zero.  I don't think that you should expect

	typedef enum {False, True} bool;
	struct { bool flag : 1; } var;

to even compile, because compilers are currently required to only support
int bit fields.
					Kenneth Almquist

gnu@sun.uucp (John Gilmore) (02/29/84)

The revised C Reference Manual (of June 83) says "The language does not
restrict the types of things that are declared as fields, but
implementations are not required to support any but <unsigned int>
fields."

If you are writing a portable program, declare your bit fields unsigned.
Programs which declare them "int" are asking for trouble.

Apparently the idea that the language could validly transmogrify "int"
bitfields into "unsigned int" has been recanted.  Good riddance to it.
(A *compiler* could, as an extension to the language, allow you to say
"int" and actually do "unsigned int" -- but at least now it's not part
of the language definition.)

It's a shame there are no unsigned enums.  Seems like a natural;
in fact, if none of the elements are negative, it should figure it out
by itself.

turner@ucbesvax.UUCP (03/09/84)

/* C hackers: why does this abort?  (Don't peek at the answer below.)	*/
typedef enum {False, True} bool;

main() {		/*       note the single-bit-field below */
	struct { bool flag : 1; } var;

	var.flag = True;
	if (var.flag != True ) abort ( );
}
/*	*	*	*	*	*	*	*	*	*/

Give up?  Well, except for type-checking, enum bools "are treated as if
they were int" [1] in the Ritchie C compiler; this is the only guideline
on the question of enum signedness.  The single-bit field may or may not
be considered signed [2].  If it is signed, the flag bit is read out and
sign-extended.  For 4.2 BSD pcc, var.flag == (bool) (-1).  Now try

	    if ( (var.flag = True) != True) abort ( );

With 4.2 pcc, this doesn't abort--I suppose because the compiler is "smart"
about assigning constants and then comparing results within a certain window.

If you are a crypto-Wirthite strong-typing warrior in the Jihad against
Dangerous and Sacrilegious Programming Styles (like me), I highly recommend
using one of the following forms for Boolean typedefs:

/*	*	*	*	*	*	*	*	*	*/
#if pdp11 || ...	/* ... any machine with unsigned bit-fields	*/
#define __TRUE__ 1	/* non-sign-extended TRUE			*/
#else
#define __TRUE__ (-1)	/* sign-extended TRUE				*/
#endif

typedef enum {TRUE=__TRUE__, FALSE=0} bool;	/* crypto-Wirthite	*/
typedef enum {true=__TRUE__, false=0} Boolean;	/* Fundamentalist	*/
/*	*	*	*	*	*	*	*	*	*/

A suggestion to the C ANSI standards committee: to the extent that they are
defining the C preprocessor, I would like to see __TRUE__ available from cpp,
rather than be forced to use "#if this-machine-or-that" hacks.

This form could extend to any machine dependency allowed by the prevailing
language definition.  I would, for the example above, happily settle for the
having __UBITFIELD__ auto-defined when bit fields are always unsigned; maybe
we could have __SCHAR__ for when there is no unsigned char, __CHARSX__ for
when char always gets sign-extended, and so on.  The "compiler control
lines" have a bastard status within the language definition.  Perhaps in
formalizing it, some of these issues could be addressed.

Living on the west coast, I can't make it to *one* ANSI committee meeting,
much less two in a row.  Perhaps someone with a vote there could bring this
issue up for me?
---
[1] "Recent Changes to C", D. M. Ritchie, Nov 15, 1978.
[2] "The C Programming Language--Reference Manual", D. M. Ritchie, p. 13.
---
Michael Turner (ucbvax!ucbesvax.turner)