比特字段与整体促销 [英] Bit-fields vs integral promotions

查看:65
本文介绍了比特字段与整体促销的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我正在使用int为16位的实现。在下面的

程序中,在第一种情况下调用了什么函数,在第二种情况下调用了什么是
?另外,如果C89

和C99之间存在差异,我想知道。我尝试过不同的编译器,

,我看到了一些差异。在我向我的C

供应商提交错误报告之前,我想知道正确的行为是什么。


struct S

{

未签名a:4;

未签名b:16;

};


foo();

bar();


main()

{

struct s s;

sa = sb = 0;


if(sa - 5< 0)foo();

else bar();


if(sb - 5< 0)foo();

else bar();

}

解决方案

2007年8月23日星期四18:08:29 +0200(CEST),瑟斯顿曼森
在comp.lang.c中
< ma ***** @ mailinator.comwrote:


假设我正在使用一个int的实现是16位。在下面的

程序中,在第一种情况下调用了什么函数,在第二种情况下调用了什么是
?另外,如果C89

和C99之间存在差异,我想知道。我尝试过不同的编译器,

,我看到了一些差异。在我向我的C

供应商提交错误报告之前,我想知道正确的行为是什么。


struct S

{

未签名a:4;

未签名b:16;

};


foo();

bar();


main()



既然你提到C99,我会指出两个声明和

上面main()的定义在C99中是非法的。隐含的int是从C99语言中删除的



{

struct S s;

sa = sb = 0;


if(sa - 5< 0)foo();

else bar();


if(sb - 5< 0)foo();



在向C供应商提交错误报告之前,我建议

考虑到正确的行为。是给程序员

写的:


if((int)sb - 5< 0)foo();

....或:


if((unsigned)sb - 5< 0)foo();


....并明确表达所需的行为。


else bar();

}



顺便说一句,这可能会更好地在comp.std.c上询问。我是

在那里交叉发布这个回复,看看它引出了什么评论。


至于在平台上保留16位的无符号位字段其中int

有16位,这很清楚。它必须提升为unsigned int,

因此s.b - 5变为(unsigned int)(UINT_MAX - 4),否则

称为65531.


无符号int位字段的提升,其位数少于

有符号整数中的值位数更具争议性。


不幸的是,关于位域的C90标准的措辞

模糊不清,含糊不清。 C99标准的措辞已经改变并添加了更多细节,主要是由于添加了_Bool

和< stdint.hinteger类型,但至少它具体

提到整数促销中的位字段。有些人认为它仍然含糊不清,但我认为很清楚。


我会从C99开始(这更容易引用PDF文件):


====

6.3.1算术操作数

6.3.1.1布尔值,字符和整数

1每个整数类型的整数转换等级定义为

如下:

?没有两个有符号整数类型具有相同的等级,即使它们具有相同的表示形式。

?有符号整数类型的等级应大于

的等级,任何带有精度较低的有符号整数类型。

? long long int的等级应大于long $ / b $ b int的等级,该等级应大于int的等级,其应大于等于的等级。 short int,它应该大于签名字符的

等级。

?任何无符号整数类型的等级应等于

对应的有符号整数类型的等级(如果有的话)。

?任何标准整数类型的等级应大于具有相同宽度的任何扩展整数类型的等级



? char的等级应等于signed char和unsigned的等级

char。

? _Bool的等级应小于所有其他标准

整数类型的等级。

?任何枚举类型的等级应等于

兼容整数类型的等级(见6.7.2.2)。

?任何扩展有符号整数类型相对于另一个具有相同精度的扩展有符号整数类型的等级是

实现定义,但仍受其他规则的约束/>
确定整数转换排名。

?对于所有整数类型T1,T2和T3,如果T1的排名高于T2

且T2的排名高于T3,则T1的排名高于T3


2如果可以使用int或

unsigned int,则可以在表达式中使用以下内容:

?具有整数类型的对象或表达式,其整数

转换等级小于int和unsigned int的等级。

?一个_Bool,int,signed int或unsigned int类型的位字段。


如果int可以表示原始类型的所有值,则值为

转换为int;否则,它将转换为unsigned int。


这些称为整数提升。所有其他类型都没有变化

整数促销。

====


注意第2段中的最后一个要点,指定

位字段int,signed int,unsigned int,以及仅在C99中,_ Bool,

参与整数提升。接下来是整数促销的

定义,即如果

原始类型的所有值都在signed int的范围内,


接下来,在C99中,我们得到了位域的定义,6.7.2.1 P9:


====

A位字段被解释为有符号或无符号整数类型

由指定的位数组成。

====


现在将它们绑在一起,我们有6.2.6.2 P6:


====

整数类型的精度是位数它使用

表示值,不包括任何符号和填充位。

整数类型的宽度是相同的,但包括任何符号位;因此对于无符号

整数类型,两个值是相同的,而对于有符号整数

类型,宽度比精度大一个。

====


所以在C99中,即使是_Bool,int,signed int或

unsigned int类型的位字段参与整数促销活动,如果一个int可以代表原始的

类型的所有值,则转换为

到登录,但是已经有相当多的讨论关于是否

原始类型表示:


1.原始类型 unsigned int位字段的无符号int,

,无论使用的位数是否小于signed int中的

值位,所以unsigned int bit-field总是

提升为unsigned int。即使
实际上适合小的无符号int位域的所有值都在int可以容纳的值的范围内。


2.原始类型是用户定义的无符号整数类型

由指定的位数组成。


当精度考虑因素时似乎没有那么模糊因为

,unsigned int位字段被解释了。由

指定的位数组成,其精度就是位数。


并且有一个明确的声明,即等级有符号整数

类型应大于任何有符号整数类型的等级,其中

精度较低连同任何无符号整数类型的等级

应等于相应的有符号整数类型的等级。


所以sa的精度为4,并且在实现上签名int

指定的精度为15,这意味着它的排名小于

signed或unsigned int,因此应该提升为signed int

因为所有可以放在unsigned int中且值为
精度为4的值都在signed int范围内。


有一些论点认为这种推理链断裂了

,因为它基于解释这个词,实际上并不是由
定义的标准,至少不是在这种情况下使用的。


对于C90,事情甚至比较混乱。


关于整数的整个部分促销6.2.1.1是:


====

char,short int或int位字段,或者他们的签名或者

无符号变量或具有枚举类型的对象可以在表达式中使用,只要可以使用int或unsigned int。如果

int可以表示原始类型的所有值,则值为

转换为int;否则它将转换为unsigned int。

这些被称为整体促销。


积分促销保留包括标志在内的价值。正如之前讨论过的那样,简单字符是否被视为签名是

实现定义。

=== ==


关于位字段的陈述与C99几乎相同,位字段

被解释为由...组成的整数类型指定数字

位。


C90未提及rank或precision。对于整数类型基于价值位数的



因此C90中的标志杆数量较少,所有人都可以继续使用的是一个人的

关于原始类型的意见unsigned:4:是

" unsigned"或者解释或解释类型可以保存从0到

16的值。


我的个人意见是两个版本的意图是

unsigned int位字段具有与已签名的值相同的值位数

int或更少,应该提升为signed int。


我有同意发布的情绪,即

标准的规范性文本实际上并未确切地说明,尽管人们可以为C99做出比C90更强的案例。


至于提交错误报告,如果您的编译器供应商

不同意您的信息,请不要感到惊讶。


我曾经测试过的每个编译器总是将无符号的
位字段提升为无符号整数,无论​​位数如何。这个

包括至少Microsoft VC ++ 6.0和2005 Express,Borland C ++


因此,即使你同意sa应该提升为signed int,也要准备好听到标准含糊不清,尤其是C90,并且

也是大多数编译器将它推广到未签名。


-

Jack Klein

主页: http://JK-Technology.Com

常见问题解答

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


Ĵ ack Klein写道:


>

至于在平台上保持16位的无符号位域,其中int

有16位,这很清楚。它必须提升为unsigned int,

因此s.b - 5变为(unsigned int)(UINT_MAX - 4),否则

称为65531.



它不是那么清楚。 />
如果signed int可以保存unsigned int的所有值(IIRC,那么

平台没有native无符号算术,这就是

case),然后,它应该被提升为int。


-

你可以通过< ta *******与我联系********* *@yahoDELETETHATo.fr>


星期五,2007年8月24日11:03:54 +0200,AndréGillibert

< ta ***************** @ yahodeletethato.frwrote在comp.std.c:


Jack Klein写道:



至于在平台上保持16位的无符号位域,其中int

有16位,这很清楚。它必须提升为unsigned int,

因此s.b - 5变为(unsigned int)(UINT_MAX - 4),否则

称为65531.



它不是那么清楚。 />
如果signed int可以保存unsigned int的所有值(IIRC,那么

平台没有native无符号算术,这就是

case),然后,它应该被提升为int。



请注意,我特意说在int有16

位的平台上。你所提到的平台必须至少有17位在

a签署的int。


-

Jack Klein

主页: http://JK-Technology.Com

常见问题解答

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


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();
}

解决方案

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


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>


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


这篇关于比特字段与整体促销的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆