Is it true that with 32-bit int, and 64-bit long long,

and given the type

struct { unsigned long long x:40; } x;

no promotion occurs in the expression

x.a + x.a

its result is a 40-bit type, i.e. the result of the

addition truncates to 40 bits. This belief appears to

derive from detailed reading of 6.3.1.1, 6.3.1.8 and

6.7.2.1#9.

I find this all hard to accept, it seems counter-

intuitive, non-C-like (if first-class bit-sized types

are something we want, why not have them

smaller than int too?), and almost certainly not

true in C++.

Yet gcc seems to be heading that way. See for

example the regression test at

http://www.yqcomputer.com/

An implementation is free is do that as an extension, but Standard C

does not support bit-fields of type unsigned long long.

--

Thad

XXXX@XXXXX.COM a rit :

Mmm could you please elaborate?

"counter-intuitive" is surely not. What is so surprising?

You add 40 bits number to obtain a 40 bits result. Seems

100% normal and "C-like" to me.

Anyway what is the result of:

struct { unsigned a:10; } x,result;

result.a = x.a+x.a; // --> ???

It is an addition truncated to 10 bits, I am sorry...

6.7.2.1p4: "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."

The width in a bit field declaration only controls how the value of

that member is stored. Once that value is retrieved, it has no effect

on the type of the expression which accesses that member. If the

declared type of 'a' were one that is legal for a bit-field, then the

type and value of the expression x.a+x.a would be determined by exactly

the same rules that would apply if the ":40" were removed from the

declaration of 'a'.

It's true that no promotion occurs but it's false that the result is a

40-bit type. I think a better example for you is:

struct {

unsigned long long a : 2;

} x;

+x.a

Q: Is an implementation allowed to have the type of that expression be

int?

A: No, it must be unsigned long long (ignoring compiler extensions).

Bit-fields are just an attribute used for controlling bit-packing and

padding so you can just think of them as regular integer types with

some restrictions (sizeof and the address operator mainly). To convince

yourself of this, read the definition of integer type (6.2.5) and see

that it doesn't include bit-fields as separate types, so all the parts

in 6.3 that deal with integer rank/conversions/promotions don't care

about the bit-field width, just the type (though there is one stupidity

of C to remember: the compiler is allowed to treat plain integers as

unsigned in bit-fields, but that just acts as if you specified it with

unsigned).

As other posters have pointed out, unsigned long long bitfields are

an implementation-defined extension.

However, based on the way ISO C handles integer promotions, it

seems that what _should_ happen is that the result of the

addition is a full unsigned long long (64-bit) untruncated result.

Obviously, assigning that result to a 40-bit bitfield will then

result in truncation, but the intermediate result of the addition

should (probably) not be truncated. I add the "probably"

caveat because the whole thing falls under "implemenation-defined

behavior", and you could argue that GCC is conforming in

that regard, even if it is unintuitive.

-drt

A bit-field member has a storage type only; in expressions

it is promoted to a "normal" integer type, which combines

according to the usual rules. If the result of an expression

is stored into a bit-field member and is not representable,

then of course u.b. occurs.

"DAGwyn" < XXXX@XXXXX.COM > writes:

Is it undefined behavior, or is it merely the implementation-defined

result or implementation-defined signal that results from a conversion

(or well-defined range reduction if the bit-field is unsigned)?

--

Keith Thompson (The_Other_Keith) XXXX@XXXXX.COM < http://www.yqcomputer.com/ ~kst>

San Diego Supercomputer Center <*> < http://www.yqcomputer.com/ ~kst>

We must do something. This is something. Therefore, we must do this.

Is it undefined behavior, or is it merely the implementation-defined

result or implementation-defined signal that results from a conversion

(or well-defined range reduction if the bit-field is unsigned)?

--

Keith Thompson (The_Other_Keith) XXXX@XXXXX.COM < http://www.yqcomputer.com/ ~kst>

San Diego Supercomputer Center <*> < http://www.yqcomputer.com/ ~kst>

We must do something. This is something. Therefore, we must do this.

XXXX@XXXXX.COM writes:

[ struct { unsigned long long a:40; } x; /* correction */ ]

What matters is 6.7.2.1 p9: "A bit-field is interpreted as a signed

or unsigned integer type consisting of the specified number of bits."

Considering the set of people who posted this comment or something

similar, it's probably some sort of C folklore. But it's not what

the Standard says.

The type of 'x.a' is a 40-bit (unsigned) integer type (6.7.2.1 p9).

The expression 'x.a + x.a' first goes through the integer promotions

for each of the two operands. Assuming that an 'int' is only 32 bits,

the integer promotions leave the 40-bit types unchanged (6.3.1.1 p2).

The plus operator then applies the usual arithmetic conversions. The

two (promoted) operands both have the same 40-bit (unsigned) integer

type, so the usual arithmetic conversions leave the types unchanged

(6.3.1.8 p1).

The result of the plus operator has type that is the type of the

operands after the conversions. "Unless explicitly stated otherwise,

the common real type is also the corresponding real type of the

result, ..." (6.3.1.8 p1).

Hence the type of 'x.a + x.a' is a 40-bit unsigned integer type. If

unsigned long long has 64 bits, then the result may be different than

what would be obtained if the result type were unsigned long long.

Some examples (assuming 32-bit ints, 64 bit long longs):

1. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = {0};

if( x.a - 1LL < 0 ) printf( "less\n" );

else printf( "not less\n" );

2. Will "less" or "not less" be printed?

struct { unsigned long long a:2; } x = {0};

if( x.a - 1 < 0 ) printf( "less\n" );

else printf( "not less\n" );

3. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = {0};

if( (x.a + x.a) - 1LL < 0 ) printf( "less\n" );

else printf( "not less\n" );

4. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = { 0x8000000000uLL };

if( (x.a + x.a) < x.a ) printf( "less\n" );

else printf( "not less\n" );

The answer in every case is "less". If the (promoted or converted)

type of x.a in the expressions were type 'unsigned long long', the

answers would be "not less". Note that example 2 can be tried with

'unsigned' in place of 'unsigned long long', in case someone doesn't

have access to a compiler that supports extended bitfield types.

[ struct { unsigned long long a:40; } x; /* correction */ ]

What matters is 6.7.2.1 p9: "A bit-field is interpreted as a signed

or unsigned integer type consisting of the specified number of bits."

Considering the set of people who posted this comment or something

similar, it's probably some sort of C folklore. But it's not what

the Standard says.

The type of 'x.a' is a 40-bit (unsigned) integer type (6.7.2.1 p9).

The expression 'x.a + x.a' first goes through the integer promotions

for each of the two operands. Assuming that an 'int' is only 32 bits,

the integer promotions leave the 40-bit types unchanged (6.3.1.1 p2).

The plus operator then applies the usual arithmetic conversions. The

two (promoted) operands both have the same 40-bit (unsigned) integer

type, so the usual arithmetic conversions leave the types unchanged

(6.3.1.8 p1).

The result of the plus operator has type that is the type of the

operands after the conversions. "Unless explicitly stated otherwise,

the common real type is also the corresponding real type of the

result, ..." (6.3.1.8 p1).

Hence the type of 'x.a + x.a' is a 40-bit unsigned integer type. If

unsigned long long has 64 bits, then the result may be different than

what would be obtained if the result type were unsigned long long.

Some examples (assuming 32-bit ints, 64 bit long longs):

1. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = {0};

if( x.a - 1LL < 0 ) printf( "less\n" );

else printf( "not less\n" );

2. Will "less" or "not less" be printed?

struct { unsigned long long a:2; } x = {0};

if( x.a - 1 < 0 ) printf( "less\n" );

else printf( "not less\n" );

3. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = {0};

if( (x.a + x.a) - 1LL < 0 ) printf( "less\n" );

else printf( "not less\n" );

4. Will "less" or "not less" be printed?

struct { unsigned long long a:40; } x = { 0x8000000000uLL };

if( (x.a + x.a) < x.a ) printf( "less\n" );

else printf( "not less\n" );

The answer in every case is "less". If the (promoted or converted)

type of x.a in the expressions were type 'unsigned long long', the

answers would be "not less". Note that example 2 can be tried with

'unsigned' in place of 'unsigned long long', in case someone doesn't

have access to a compiler that supports extended bitfield types.

"Me" < XXXX@XXXXX.COM > writes:

The rules for precision, integer conversion rank, and integer promotions

together require that the result type be 'int'.

Did you even bother to read 6.7.2.1 p9?

The rules for precision, integer conversion rank, and integer promotions

together require that the result type be 'int'.

Did you even bother to read 6.7.2.1 p9?

"David R Tribble" < XXXX@XXXXX.COM > writes:

Do you accept that the type of x.a is a 40-bit (unsigned) integer

type? Have you read 6.7.2.1 p9?

Assuming you accept that the type of x.a is a 40-bit integer

type, how do you get that the type of 'x.a + x.a' is anything

other than that same 40-bit type?

Do you accept that the type of x.a is a 40-bit (unsigned) integer

type? Have you read 6.7.2.1 p9?

Assuming you accept that the type of x.a is a 40-bit integer

type, how do you get that the type of 'x.a + x.a' is anything

other than that same 40-bit type?

David R Tribble writes:

Yeah, just now:

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

consisting of the specified number of bits.

But that does not affect what I _think_ should happen.

True, a literal reading of the standard certainly implies that bitfield

values larger than unsigned int will be treated as n-bit types,

where n is more than the bits in an unsigned long.

This could be read as a back-door way to force the compiler

to implement n-bit integer types, for arbitrary n between the

sizes of int and long long int.

But "the spirit of C" is what makes me think that the bitfield

operands within the expression _should_ be converted into

full-sized standard integer types, i.e, unsigned long long.

It should be clear that my "should" in the sentence above is

my opinion about what _should_ happen and not what _does_

happen.

-drt

Yeah, just now:

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

consisting of the specified number of bits.

But that does not affect what I _think_ should happen.

True, a literal reading of the standard certainly implies that bitfield

values larger than unsigned int will be treated as n-bit types,

where n is more than the bits in an unsigned long.

This could be read as a back-door way to force the compiler

to implement n-bit integer types, for arbitrary n between the

sizes of int and long long int.

But "the spirit of C" is what makes me think that the bitfield

operands within the expression _should_ be converted into

full-sized standard integer types, i.e, unsigned long long.

It should be clear that my "should" in the sentence above is

my opinion about what _should_ happen and not what _does_

happen.

-drt

"David R Tribble" < XXXX@XXXXX.COM > writes:

Ahh, ok.

I presume you meant where n is more than the bits in an unsigned int.

The reading I'm suggesting doesn't force a compiler to implement such

types, since bitfields of type larger than signed/unsigned int are

an extension, not a requirement.

For non-bitfield types: types shorter than signed/unsigned int are

promoted to one of the int types, and types longer than an int type

operate in the smallest type that's at least as large as each of the

operands.

Given that, can you explain what's wrong with having the same rule for

bitfields as for non-bitfields?

Yes, I appreciate the clarification.

Ahh, ok.

I presume you meant where n is more than the bits in an unsigned int.

The reading I'm suggesting doesn't force a compiler to implement such

types, since bitfields of type larger than signed/unsigned int are

an extension, not a requirement.

For non-bitfield types: types shorter than signed/unsigned int are

promoted to one of the int types, and types longer than an int type

operate in the smallest type that's at least as large as each of the

operands.

Given that, can you explain what's wrong with having the same rule for

bitfields as for non-bitfields?

Yes, I appreciate the clarification.

im Rentsch wrote:

The standard doesn't say what "interpreted" means in this context. I

think it means for the initial read or the final write, it treats it as

a integer type with whatever bits, you think it creates a new integer

type. Both are valid interpretations (puns are fun), but IMHO the

standard doesn't really have wording to take account for it in most of

6.3.

I'm kind of agreeing with you, but I'm kind of not. The simplest place

to start is:

6.3.1.1/2 "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"

My guess is that the comittee intended:

struct {

unsigned a : 2;

} i;

+i.a;

to promote to int as opposed to unsigned int. I would argue this is

wrong because I take "type" to mean "integer type" (and because I'm a

fan of unsigned preserving conversions), but I can see why they would

want it to act like that. So if I would have to guess, this is one of

the places the "interpreted" part of 6.7.2.1/9 takes place. But this

leads to two tricky examples to compare against the current wording:

(assume 32-bit int, 64-bit long, and 64-bit long long)

////////////////////////

struct {

unsigned long a : 51;

unsigned long b : 50;

} x;

x.a + x.b; // #A#

/////////////////////////

struct {

unsigned long a : 50;

unsigned long long b : 40;

} y;

y.a + y.b; // #B#

6.3.1.8/1:

- If both operands have the same type, then no further conversion is

needed.

(my interpretation)

#A# - Both operands stay as unsigned long and no further conversion is

needed

(your interpretation)

#A# - unsigned long : 51 is different than unsigned long : 50, so

further conversion is needed.

- Otherwise, if both operands have signed integer types or both have

unsigned integer types, the operand with the type of lesser integer

conversion rank is converted to the type of the operand with greater

rank.

(your interpretation)

#A# - Ok, now we need 6.3.1.1/1, which talks about conversion ranks

which involve the integer types (6.2.5). Neither sections take

bit-fields into account, so now what?

#B# - Ditto, but this one is more trickier because unsigned long : 50

is larger in width than unsigned long long : 40 but the rank of long is

smaller than long long.

The standard doesn't say what "interpreted" means in this context. I

think it means for the initial read or the final write, it treats it as

a integer type with whatever bits, you think it creates a new integer

type. Both are valid interpretations (puns are fun), but IMHO the

standard doesn't really have wording to take account for it in most of

6.3.

I'm kind of agreeing with you, but I'm kind of not. The simplest place

to start is:

6.3.1.1/2 "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"

My guess is that the comittee intended:

struct {

unsigned a : 2;

} i;

+i.a;

to promote to int as opposed to unsigned int. I would argue this is

wrong because I take "type" to mean "integer type" (and because I'm a

fan of unsigned preserving conversions), but I can see why they would

want it to act like that. So if I would have to guess, this is one of

the places the "interpreted" part of 6.7.2.1/9 takes place. But this

leads to two tricky examples to compare against the current wording:

(assume 32-bit int, 64-bit long, and 64-bit long long)

////////////////////////

struct {

unsigned long a : 51;

unsigned long b : 50;

} x;

x.a + x.b; // #A#

/////////////////////////

struct {

unsigned long a : 50;

unsigned long long b : 40;

} y;

y.a + y.b; // #B#

6.3.1.8/1:

- If both operands have the same type, then no further conversion is

needed.

(my interpretation)

#A# - Both operands stay as unsigned long and no further conversion is

needed

(your interpretation)

#A# - unsigned long : 51 is different than unsigned long : 50, so

further conversion is needed.

- Otherwise, if both operands have signed integer types or both have

unsigned integer types, the operand with the type of lesser integer

conversion rank is converted to the type of the operand with greater

rank.

(your interpretation)

#A# - Ok, now we need 6.3.1.1/1, which talks about conversion ranks

which involve the integer types (6.2.5). Neither sections take

bit-fields into account, so now what?

#B# - Ditto, but this one is more trickier because unsigned long : 50

is larger in width than unsigned long long : 40 but the rank of long is

smaller than long long.

1. bit-fields and integral promotions

2. Nesting IF's and AND's - a bit of help please...

3. 32-bit data types vs. 16-bit/8-bit

4. retrieving processor type (32 bit/64 bit) on 32 bit OS

5. Concatenating date field into text ands using in a formula

6. Highorder bits of bit field go to bit bucket

7. TYPE IN ONE FIELD, INFO TYPED SHOWS UP IN ANOTHER FIELD

8. Using Wildcards on Bit type fields

9. bit fields that do not fit in a built-in type

10. [PATCH 2/8] imx: serial: fix one bit field type

11. Using a CheckBox in a DataGrid to Update a Bit Type Data Field

12. Subscriber not updated when filtering a publication on a bit type field

13. VEA 2005 should allow indices to include fields of data type bit

15. [PATCH 2/9 -v2] imx: serial: fix one bit field type