On Thu, 23 Aug 2007 18:08:29 +0200 (CEST), Thurston Manson

<(E-Mail Removed)> wrote in comp.lang.c:

> Suppose I'm using an implementation where an int is 16 bits. In the

> program below, what function is called in the first case, and what is

> called in the second case? Also, if there is a difference between C89

> and C99, I would like to know. I have tried with different compilers,

> and I see some differences. Before I file a bug report with my C

> vendor, I would like to know what the correct behavior is.

>

> struct S

> {

> unsigned a:4;

> unsigned b:16;

> };

>

> foo();

> bar();

>

> main()
Since you mentioned C99, I'll point out that the two declarations and

the definition of main() above are illegal in C99. Implicit int was

removed from the language in C99.

> {

> struct S s;

> s.a = s.b = 0;

>

> if (s.a - 5 < 0) foo();

> else bar();

>

> if (s.b - 5 < 0) foo();
Before you file a bug report with your C vendor, I'd suggest

considering that the "correct behavior" is for the programmer to

write:

if ((int)s.b - 5 < 0) foo();

....or:

if ((unsigned)s.b - 5 < 0) foo();

....and make the desired behavior explicit.

> else bar();

> }
This would probably be better asked on comp.std.c, by the way. I'm

cross posting this reply there, to see what comment it elicits.

As for an unsigned bit-field holding 16 bits on a platform where int

has 16 bits, this is quite clear. It must promote to unsigned int,

therefore "s.b - 5" becomes (unsigned int)(UINT_MAX - 4), otherwise

known as 65531.

The promotion of an unsigned int bit-field with fewer bits than the

number of value bits in a signed int is more controversial.

Unfortunately, the wording of the C90 standard concerning bit-fields

is obscure and rather ambiguous. The wording of the C99 standard has

changed and added more specifics, mainly due to the addition of _Bool

and the <stdint.h> integer types, but at least it specifically

mentions bit-fields in the integer promotions. Some feel that it is

still ambiguous, but I think it is pretty clear.

I'll start with C99 (which is easier to quote from the PDF file):

====

6.3.1 Arithmetic operands

6.3.1.1 Boolean, characters, and integers

1 Every integer type has an integer conversion rank defined as

follows:

— No two signed integer types shall have the same rank, even if they

have the same representation.

— The rank of a signed integer type shall be greater than the rank of

any signed integer type with less precision.

— The rank of long long int shall be greater than the rank of long

int, which shall be greater than the rank of int, which shall be

greater than the rank of short int, which shall be greater than the

rank of signed char.

— The rank of any unsigned integer type shall equal the rank of the

corresponding signed integer type, if any.

— The rank of any standard integer type shall be greater than the rank

of any extended integer type with the same width.

— The rank of char shall equal the rank of signed char and unsigned

char.

— The rank of _Bool shall be less than the rank of all other standard

integer types.

— The rank of any enumerated type shall equal the rank of the

compatible integer type (see 6.7.2.2).

— The rank of any extended signed integer type relative to another

extended signed integer type with the same precision is

implementation-defined, but still subject to the other rules for

determining the integer conversion rank.

— For all integer types T1, T2, and T3, if T1 has greater rank than T2

and T2 has greater rank than T3, then T1 has greater rank than T3

2 The following may be used in an expression wherever an int or

unsigned int may be used:

— An object or expression with an integer type whose integer

conversion rank is less than the rank of int and unsigned int.

— A bit-field of type _Bool, int, signed int, or unsigned int.

If an int can represent all values of the original type, the value is

converted to an int; otherwise, it is converted to an unsigned int.

These are called the integer promotions. All other types are unchanged

by the integer promotions.

====

Notice the last bullet point in paragraph 2, that specifies that

bit-fields of int, signed int, unsigned int, and, in C99 only, _Bool,

participate in the integer promotions. This is followed by the

definition of integer promotions, namely that if all values of the

original type are within the range of signed int,

Next, in C99, we get to the definition of bit-fields, 6.7.2.1 P9:

====

A bit-field is interpreted as a signed or unsigned integer type

consisting of the specified number of bits.

====

Now to tie this together, we have 6.2.6.2 P6:

====

The precision of an integer type is the number of bits it uses to

represent values, excluding any sign and padding bits. The width of an

integer type is the same but including any sign bit; thus for unsigned

integer types the two values are the same, while for signed integer

types the width is one greater than the precision.

====

So in C99, even though "A bit-field of type _Bool, int, signed int, or

unsigned int" participates in the integer promotions, it is converted

to signed in if "an int can represent all values of the original

type", but there has been quite some discussion about whether "the

original type" means either:

1. The "original type" of an unsigned int bit-field is unsigned int,

regardless of the fact that the number of bits used is less than the

value bits in a signed int, so an unsigned int bit-field always

promotes to unsigned int. Even though all the values that can

actually fit into a small unsigned int bit-field are within the range

of values that an int can hold.

2. The "original type" is the user-defined "unsigned integer type

consisting of the specified number of bits."

There seems to be less ambiguity when precision is factored in. Since

the unsigned int bit-field is "interpreted" as consisting of the

specified number of bits, its precision is that number of bits.

And there is the clear statement that "the rank of a signed integer

type shall be greater than the rank of any signed integer type with

less precision" together with "the rank of any unsigned integer type

shall equal the rank of the corresponding signed integer type."

So s.a has a precision of 4, and signed int on the implementation you

specified has a precision of 15, which means it has a lesser rank than

signed or unsigned int, and therefore should promote to signed int

because all the values that can fit in an unsigned int with a

precision of 4 are in the range of signed int.

There has been some argument that this chain of reasoning falls apart

because it is based on the word "interpreted", which is not actually

defined by the standard, at least not as used in this context.

For C90, things are even muddier.

The entire section on the integer promotions 6.2.1.1 is:

====

A char, a short int, or an int bit-field, or their signed or

unsigned varieties, or an object that has enumeration type, may be

used in an expression wherever an int or unsigned int may be used. If

an int can represent all values of the original type, the value is

converted to an int; otherwise it is converted to an unsigned int.

These are called the integral promotions.

The integral promotions preserve value including sign. As

discussed earlier, whether a ``plain'' char is treated as signed is

implementation-defined.

=====

The statement about bit-fields is nearly the same as C99, "A bit-field

is interpreted as an integral type consisting of the specified number

of bits."

C90 makes no mention of "rank", or "precision" for integer types based

on number of value bits.

So there are fewer sign posts in C90, all one can go on is one's

opinion about whether the "original type" of "unsigned: 4:" is

"unsigned" or an "interpreted" type that can hold the values from 0 to

16.

My personal opinion is that the intent in both versions is that an

unsigned int bit-field with the same number of value bits as a signed

int, or fewer, should promote to signed int.

I have to agree with posted sentiments that the normative text of the

standard does not actually state that conclusively, although one can

make a stronger case for C99 than for C90.

As for filing a bug report, don't be surprised if your compiler vendor

disagrees with you.

Every compiler I have ever tested this on always promotes unsigned

bit-fields to unsigned int, regardless of the number of bits. This

includes at least Microsoft VC++ 6.0 an 2005 Express, Borland C++

Builder X, Peles C, and MinGW.

So even if you agree that s.a should promote to signed int, be

prepared to hear that the standard is ambiguous, especially C90, and

also that most compilers promote it to unsigned.

--

Jack Klein

Home:

http://JK-Technology.Com
FAQs for

comp.lang.c

http://c-faq.com/
comp.lang.c++

http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++

http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html