473,414 Members | 1,772 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,414 software developers and data experts.

Bit-fields vs integral promotions

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()
{
struct S s;
s.a = s.b = 0;

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

if (s.b - 5 < 0) foo();
else bar();
}

Aug 23 '07 #1
14 2097
On Thu, 23 Aug 2007 18:08:29 +0200 (CEST), Thurston Manson
<ma*****@mailinator.comwrote 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.hinteger 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
Aug 24 '07 #2
Jack Klein wrote:
>
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.
It's not that clear.
If signed int can hold all the values of unsigned int (IIRC, there are
platforms without "native" unsigned arithmetic for which this is the
case), then, it should be promoted to int.

--
You can contact me at <ta*****************@yahoDELETETHATo.fr>
Aug 24 '07 #3
On Fri, 24 Aug 2007 11:03:54 +0200, "André Gillibert"
<ta*****************@yahodeletethato.frwrote in comp.std.c:
Jack Klein wrote:

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.

It's not that clear.
If signed int can hold all the values of unsigned int (IIRC, there are
platforms without "native" unsigned arithmetic for which this is the
case), then, it should be promoted to int.
Please note that I specifically said "on a platform where int has 16
bits". A platform such as you allude to must have at least 17 bits in
a signed int.

--
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
Aug 24 '07 #4
Jack Klein wrote:
Please note that I specifically said "on a platform where int has 16
bits". A platform such as you allude to must have at least 17 bits in
a signed int.
Yep. 18 bits machine did exist... I doubt that there has ever been any 18
bits machine with 1 padding bit, and one sign bit, without unsigned
arithmetic.

Anyway, the standard *permits* that, even if it's practically impossible
to find any existing platforms that uses such a model.

--
You can contact me at <ta*****************@yahoDELETETHATo.fr>
Aug 24 '07 #5
Thurston Manson wrote:
>
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() {
struct S s;
s.a = s.b = 0;
if (s.a - 5 < 0) foo();
else bar();
if (s.b - 5 < 0) foo();
else bar();
}
This won't even compile. foo and bar are never defined. main
should return an int (required in C99). The return is missing
(required in C90). You are comparing signed and unsigned values.
No compiler bugs have been evidenced.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
--
Posted via a free Usenet account from http://www.teranews.com

Aug 25 '07 #6
Jack Klein wrote:
>
.... snip ...
>
Please note that I specifically said "on a platform where int has
16 bits". A platform such as you allude to must have at least 17
bits in a signed int.
I don't believe you can have such without having a 17 bit unsigned
int, thus leading to a 18 bit int, and thence to an 18 bit
unsigned, and ....

I don't think use of trap bits can affect this. Unsigned to signed
conversion is always possible because of the modulo unsigned
arithmetic.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Aug 25 '07 #7
CBFalconer wrote:
Jack Klein wrote:
... snip ...
>Please note that I specifically said "on a platform where int has
16 bits". A platform such as you allude to must have at least 17
bits in a signed int.

I don't believe you can have such without having a 17 bit unsigned
int, thus leading to a 18 bit int, and thence to an 18 bit
unsigned, and ....

I don't think use of trap bits can affect this. Unsigned to signed
conversion is always possible
You may be correct (I do not have time to research the Standard to come
up with a conclusion) but not for the reason you give.

because of the modulo unsigned
arithmetic.
Modulo unsigned arithmetic only guarantees that signed to unsigned is
always possible it has nothing to say about what happens when a
sufficiently large unsigned value is converted to a signed one.
--
Note that robinton.demon.co.uk addresses are no longer valid.
Aug 25 '07 #8
CBFalconer said:
Thurston Manson wrote:
>>
<snip>
>>
struct S {
unsigned a:4;
unsigned b:16;
};

foo();
bar();

main() {
struct S s;
s.a = s.b = 0;
if (s.a - 5 < 0) foo();
else bar();
if (s.b - 5 < 0) foo();
else bar();
}

This won't even compile.
Yes, it will.
foo and bar are never defined.
So? They are implicitly declared by first use. That's enough for
compilation.
main should return an int (required in C99).
Clearly this is C90 code.
The return is missing (required in C90).
Not so. The return status is undefined, but the behaviour of the program
is not. In fact, I think that the TU is strictly conforming. I'm not
saying I approve of omitting the return statement, of course - I don't.
You are comparing signed and unsigned values.
So?
No compiler bugs have been evidenced.
Indeed.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Aug 25 '07 #9
Francis Glassborow wrote:
CBFalconer wrote:
.... snip ...
>>
I don't think use of trap bits can affect this. Unsigned to signed
conversion is always possible because of the modulo unsigned
arithmetic.

You may be correct (I do not have time to research the Standard to
come up with a conclusion) but not for the reason you give.

Modulo unsigned arithmetic only guarantees that signed to unsigned
is always possible it has nothing to say about what happens when a
sufficiently large unsigned value is converted to a signed one.
No, the standard says that any attempt to store a value outside its
capacity in a signed int is undefined behaviour.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
--
Posted via a free Usenet account from http://www.teranews.com

Aug 25 '07 #10
CBFalconer wrote:
Francis Glassborow wrote:
>CBFalconer wrote:
... snip ...
>>>
I don't think use of trap bits can affect this. Unsigned to signed
conversion is always possible because of the modulo unsigned
arithmetic.

You may be correct (I do not have time to research the Standard to
come up with a conclusion) but not for the reason you give.

Modulo unsigned arithmetic only guarantees that signed to unsigned
is always possible it has nothing to say about what happens when a
sufficiently large unsigned value is converted to a signed one.

No, the standard says that any attempt to store a value outside its
capacity in a signed int is undefined behaviour.
C&v, please.
Aug 25 '07 #11
CBFalconer writes:
>Jack Klein wrote:
>Please note that I specifically said "on a platform where int has
16 bits". A platform such as you allude to must have at least 17
bits in a signed int.

I don't believe you can have such without having a 17 bit unsigned
int, thus leading to a 18 bit int, and thence to an 18 bit
unsigned, and ....
Yes you can. C99 6.2.5p9 (Types):
"The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same."
Also 6.2.6.2p2 (Integer types):
"if there are M value bits in the signed type and N in the
unsigned type, then M <= N". [And p1 says the sign bit is
not counted as a value bit in signed types.]
I don't think use of trap bits can affect this.
C99 defines trap representations, not trap bits. Padding bits can cause
a value to be a trap representation (Note 44 in 6.2.6.2 uses a parity
bit as an example), but I think value and sign bits can too for signed
types: Negative zero, or -<type>_MAX-1 when <type>_MIN == -<type>_MAX.

--
Hallvard
Aug 25 '07 #12
CBFalconer <cb********@yahoo.comwrites:
Francis Glassborow wrote:
>CBFalconer wrote:
... snip ...
>>>
I don't think use of trap bits can affect this. Unsigned to signed
conversion is always possible because of the modulo unsigned
arithmetic.

You may be correct (I do not have time to research the Standard to
come up with a conclusion) but not for the reason you give.

Modulo unsigned arithmetic only guarantees that signed to unsigned
is always possible it has nothing to say about what happens when a
sufficiently large unsigned value is converted to a signed one.

No, the standard says that any attempt to store a value outside its
capacity in a signed int is undefined behaviour.
Not quite. Conversion to a signed type, if the value can't be
represented, yields an implementation-defined result or raises an
implementation-defined signal. (Overflowing arithmetic operations on
signed types, on the other hand, invoke undefined behavior.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Aug 25 '07 #13
Hallvard B Furuseth wrote:
CBFalconer writes:
>Jack Klein wrote:
>>Please note that I specifically said "on a platform where int has
16 bits". A platform such as you allude to must have at least 17
bits in a signed int.

I don't believe you can have such without having a 17 bit unsigned
int, thus leading to a 18 bit int, and thence to an 18 bit
unsigned, and ....

Yes you can. C99 6.2.5p9 (Types):
"The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same."
Also 6.2.6.2p2 (Integer types):
"if there are M value bits in the signed type and N in the
unsigned type, then M <= N". [And p1 says the sign bit is
not counted as a value bit in signed types.]
>I don't think use of trap bits can affect this.

C99 defines trap representations, not trap bits. Padding bits
can cause a value to be a trap representation (Note 44 in 6.2.6.2
uses a parity bit as an example), but I think value and sign bits
can too for signed types: Negative zero, or -<type>_MAX-1 when
<type>_MIN == -<type>_MAX.
Maybe I should just add a note to all my software: No protection
against M==N in 6.2.6.2p2 is afforded. :-)

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Aug 26 '07 #14
Jack Klein <jackkl...@spamcop.netwrote:
[...]
6.3.1.1 Boolean, characters, and integers
[...]
>
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.
[...]
>
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."
[...]
>
For C90, things are even muddier.
[...]
The committee has been clarified their intent through a C90 DR122:

http://www.open-std.org/jtc1/sc22/wg...cs/dr_122.html
>
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 if an implementation claiming its conformance to the standard
ignores the number of bits used for a bit-field of unsigned int type
in performing the integral promotions, it is not conforming.
--
Jun, Woong (woong at icu.ac.kr)
Samsung Electronics Co., Ltd.

``All opinions expressed are mine, and do not represent
the official opinions of any organization.''

Aug 29 '07 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: Amy DBA | last post by:
I've been asked to administer a DB2 V 8 (32-bit install) on a Solaris 64-bit platform. It seems like whomever installed DB2 on the server, goofed for not installing DB2 v8 64 bit. Do I understand...
12
by: Jean-Marc Blaise | last post by:
Hi, Is it worth to use 64-bit DB2 instances on a 32-bit kernel, in terms of: - performance - configuration (go beyond the 256 Mb segment for private mem, 1.75 Gb for Bufferpools) - other ? ...
11
by: JDeats | last post by:
1. Will there be different 64-bit .NET implementations for Intel and AMD 64-bit processors or will they share a common 64-bit CLR? 2. Will .NET managed code compiled for the 32-bit CLR be binary...
58
by: Larry David | last post by:
Ok, first of all, let's get the obvious stuff out of the way. I'm an idiot. So please indulge me for a moment. Consider it an act of "community service".... What does "64bit" mean to your friendly...
4
by: tommydkat | last post by:
Well, I've finally gotten UDB 8.2 FixPak 3 up and running on my HP-UX 11i system, thanks to Mr McBride and IBM support. :) I created a 32-bit instance and that's running just fine. However, I...
14
by: ern | last post by:
Does a function exist to convert a 128-bit hex number to a string?
14
by: =?Utf-8?B?R2Vvcmdl?= | last post by:
Hello everyone, I am using C# to develop DLL using Visual Studio 2005 and .Net 2.0, and I have no idea of how to make my DLL work with applications on 64-bit platform. Above all, I do not...
1
by: Chuck Chopp | last post by:
I have some code that is being built on the following: Windows Server 2003, both 32-bit & 64-bit editions Windows Vista, both 32-bit & 64-bit editions Windows Server 2008, both 32-bit & 64-bit...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.