Does is make sense to qualify bit fields as signed / unsigned?
if a 'bit' is signed, then you have a range of -1, 0, 1, which then becomes a ternary digit. I don't think the standard abbreviation for that would be suitable here, but makes for interesting conversations :)
I don't think Andrew is talking about single-bit bit fields. For example, 4-bit fields: 3 bits of numerical information, one bit for sign. This can entirely make sense, though I admit to not being able to come up with such a scenario off the top of my head.
Update: I'm not saying I can't think of a use for multi-bit bit fields (having used them all the time back in 2400bps modem days to compress data as much as possible for transmission), but I can't think of a use for signed bit fields, especially not a quaint, obvious one that would be an "aha" moment for readers.
Yes, it can. C bit-fields are essentially just limited-range integers. Frequently hardware interfaces pack bits together in such away that some control can go from, say, -8 to 7, in which case you do want a signed bit-field, or from 0 to 15, in which case you want an unsigned bit-field.
The relevant portion of the standard (ISO/IEC 9899:1999) is 6.7.2.1 #4:
A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.
Yes. An example from here:
struct {
/* field 4 bits wide */
unsigned field1 :4;
/*
* unnamed 3 bit field
* unnamed fields allow for padding
*/
unsigned :3;
/*
* one-bit field
* can only be 0 or -1 in two's complement!
*/
signed field2 :1;
/* align next field on a storage unit */
unsigned :0;
unsigned field3 :6;
}full_of_fields;
Only you know if it makes sense in your projects; typically, it does for fields with more than one bit, if the field can meaningfully be negative.
According to this reference, it's possible:
http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc03defbitf.htm
It's very important to qualify your variables as signed or unsigned. The compiler needs to know how to treat your variables during comparisons and casting. Examine the output of this code:
#include <stdio.h>
typedef struct
{
signed s : 1;
unsigned u : 1;
} BitStruct;
int main(void)
{
BitStruct x;
x.s = 1;
x.u = 1;
printf("s: %d \t u: %d\r\n", x.s, x.u);
printf("s>0: %d \t u>0: %d\r\n", x.s > 0, x.u > 0);
return 0;
}
Output:
s: -1 u: 1
s>0: 0 u>0: 1
The compiler stores the variable using a single bit, 1 or 0. For signed variables, the most significant bit determines the sign (high is treated negative). Thus, the signed variable, while it gets stored as 1 in binary, it gets interpreted as negative one.
Expanding on this topic, an unsigned two bit number has a range of 0 to 3, while a signed two bit number has a range of -2 to 1.
Bit masking signed types varies from platform hardware to platform hardware due to how it may deal with an overflow from a shift etc.
Any half good QA tool will warn knowingly of such usage.