比特字段和整体促销/ UAC [英] Bit-fields and integral promotion/UACs

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

问题描述




考虑以下计划:


#include< stdio.h>


int main(无效)

{

结构测试{

unsigned int x:1;

}测试;


test.x = 1;


printf("%lu \ n",(unsigned long)( test.x<<< 31));


返回0;

}


在平台上有64位长和32位整数,这打印

18446744071562067968,即一个将高33位设置为1的数字。

这让我很震惊,但我想我现在已经弄清楚会发生什么:


(1)因为位字段只有一位宽,所以它的所有值都适合一个

signed int,所以test.x转换为一。

(2)因此,shift操作的结果也是一个signed int。

(3)结果值在此平台上为负,ULONG_MAX + 1为

添加到其中,产生的值为ab ove。


这是正确的吗?

如果是,(不需要的)符号扩展名是(1)的结果,转换为

无符号位字段到signed int。然后可以通过在移位之前将位字段转换为unsigned int来轻松避免这种情况。但是,

结果程序


#include< stdio.h>


int main(void)

{

struct test {

unsigned int x:1;

} test;
< br $> b $ b test.x = 1;


printf("%lu \ n",(unsigned long)((unsigned int)test.x< < 31));

返回0;

}


仍然使用gcc 3.3.3打印相同的值。我试过的所有其他编译器

(包括gcc 4),打印2147483648,正如我原先预期的那样。我的

假设是否正确gcc 3在这里是错误的?或者我忽略了什么

并且行为实际上是实现定义的?

谢谢,

Christian

Hi,

consider the following program:

#include <stdio.h>

int main(void)
{
struct test {
unsigned int x : 1;
} test;

test.x = 1;

printf("%lu\n", (unsigned long) (test.x << 31));

return 0;
}

On a platform with 64-bit longs and 32-bit ints, this prints
18446744071562067968, i.e. a number that has the upper 33 bits set to 1.
This stunned me at first, but I think I have now figured out what happens:

(1) Because the bit-field is only one bit wide, all its values fit into a
signed int, so test.x is converted to one.
(2) Therefore, the result of the shift operation is a signed int too.
(3) Since the resulting value is negative on this platform, ULONG_MAX + 1 is
added to it, yielding the value mentioned above.

Is this correct?
If it is, the (unwanted) sign extension is the result of (1), which converts
the unsigned bit-field to a signed int. This could then easily be avoided
by casting the bit-field to an unsigned int before the shift. However, the
resulting program

#include <stdio.h>

int main(void)
{
struct test {
unsigned int x : 1;
} test;

test.x = 1;

printf("%lu\n", (unsigned long) ((unsigned int) test.x << 31));
return 0;
}

still prints the same value with gcc 3.3.3. All other compilers I have tried
(including gcc 4), print 2147483648, as I had originally expected. Is my
assumption correct that gcc 3 is wrong here? Or am I overlooking something
and the behavior is actually implementation-defined?
Thanks,
Christian

推荐答案

" Christian Kandeler" < CH **************** @ hob.de>在消息中写道

news:43 ************* @ individual.net ...
"Christian Kandeler" <ch****************@hob.de> wrote in message
news:43*************@individual.net...
#include< stdio.h>

int main(void)
{struct struct {
unsigned int x:1;
} test;

test.x = 1;

printf("%lu \ n",(unsigned long)(test.x<< 31));

返回0;
}



在64位长和32位整数的平台上,打印出来的是18446744071562067968,即将高33位设置为1的数字。
起初这让我很震惊,但我想我现在已经知道了发生了什么:

(1)因为位域只有一位宽,所有的值都是适合
signed int,因此test.x转换为一个。


是(我会说test.x的值被转换);这是整数

促销。

(2)因此,shift操作的结果也是一个signed int。


是的,因为班次结果的类型总是与

(提升)左手操作数相同。

(3)由于此平台上的结果值为负,因此会向其添加ULONG_MAX + 1
,从而产生上述值。


班次调用未定义的行为,因为左手操作数具有

签名类型,结果无法用该类型表示。


[snip]这可以通过在移位之前将位字段转换为无符号的
int来轻松避免。但是,生成的程序
[snip:添加了强制转换的前一个代码]仍然使用gcc 3.3.3打印相同的值。我已经尝试过的所有其他编译器(包括gcc 4),打印2147483648,正如我原先预期的那样。
我的假设是正确的,gcc 3在这里是错误的吗?
#include <stdio.h>

int main(void)
{
struct test {
unsigned int x : 1;
} test;

test.x = 1;

printf("%lu\n", (unsigned long) (test.x << 31));

return 0;
}

On a platform with 64-bit longs and 32-bit ints, this prints
18446744071562067968, i.e. a number that has the upper 33 bits set to 1.
This stunned me at first, but I think I have now figured out what
happens:

(1) Because the bit-field is only one bit wide, all its values fit into a
signed int, so test.x is converted to one.
Yes (I would say "the value of test.x is converted"); this is integer
promotion.
(2) Therefore, the result of the shift operation is a signed int too.
Yes, because the type of the result of a shift is always the same as the
(promoted) left-hand operand.
(3) Since the resulting value is negative on this platform, ULONG_MAX + 1
is added to it, yielding the value mentioned above.
The shift invokes undefined behaviour, because the left-hand operand has
signed type and the result cannot be represented in that type.

[snip] This could then easily be avoided by casting the bit-field to an unsigned
int before the shift. However, the resulting program [snip: previous code with cast added] still prints the same value with gcc 3.3.3. All other compilers I have
tried (including gcc 4), print 2147483648, as I had originally expected.
Is my assumption correct that gcc 3 is wrong here?




根据我的理解,是的。


Alex



By my understanding, yes.

Alex


Alex Fraser写道:
Alex Fraser wrote:

.... snip ...
.... snip ...
这可以通过在移位之前将位字段转换为
unsigned int来轻松避免。但是,生成的程序
This could then easily be avoided by casting the bit-field to an
unsigned int before the shift. However, the resulting program


[剪辑:添加了强制转换的前一个代码]



[snip: previous code with cast added]

仍然使用gcc 3.3.3打印相同的值。所有其他编译器
我试过(包括gcc 4),打印2147483648,正如我原先预计的那样。我的假设是正确的,gcc 3在这里是错的吗?
still prints the same value with gcc 3.3.3. All other compilers
I have tried (including gcc 4), print 2147483648, as I had
originally expected. Is my assumption correct that gcc 3 is
wrong here?



根据我的理解,是的。



By my understanding, yes.




自你用增加的演员剪断了(错误的)代码,很难批评b $ b批评。无论如何,我已经在下面添加了(tautened)代码:


#include< stdio.h>

int main(void){

struct test {

unsigned int x:1;

} test;


test.x = 1;

printf("%lu \ n",(unsigned long)((unsigned int)test.x<< 31));

返回0;

}


尝试:

printf("%lu \ n",((unsigned long)test.x )<<<< 31;;


第一个任务是将值1转换为无符号长格式。

之后,移位可以正常运行而不会溢出。在某种程度上,

是标准态度保值的错误,

当未签名的保存更合适时。


-

"如果你想通过groups.google.com发布一个后续内容,请不要使用

破坏的回复链接在文章的底部。点击

" show options"在文章的顶部,然后点击

回复在文章标题的底部。 - Keith Thompson

更多详细信息:< http://cfaj.freeshell.org/google/>



Since you snipped the (faulty) code with added cast, it is hard to
criticize. Anyway I have added that (tautened) code back below:

#include <stdio.h>
int main(void) {
struct test {
unsigned int x : 1;
} test;

test.x = 1;
printf("%lu\n", (unsigned long) ((unsigned int) test.x << 31));
return 0;
}

Try:
printf("%lu\n", ((unsigned long) test.x) << 31);

The first task is to get the value 1 into unsigned long form.
After that the shift can function without overflow. In part this
is the fault of the standards attitude towards value preservation,
when unsigned preservation would be more appropriate.

--
"If you want to post a followup via groups.google.com, don''t use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>


文章< 43*************@individual.net>

Christian Kandeler< ch **************** @ hob &由Matchi.com提供回到GT;写道:

[代码剪辑]
In article <43*************@individual.net>
Christian Kandeler <ch****************@hob.de> wrote:
[code snipped]
在64位长和32位整数的平台上,这打印出来的是18446744071562067968,即a将高33位设置为1的数字。
这一开始让我惊呆了,但我想我现在已经知道会发生什么:

(1)因为位字段只是一位宽,所有值都适合
signed int,因此test.x转换为一。
(2)因此,shift操作的结果也是一个signed int。
(3)由于此平台上的结果值为负,因此将ULONG_MAX + 1添加到其中,产生上述值。

这是正确的吗?


是。


ANSI / ISO C有错误字样规则(根据我的反正:-))

处理签名和未签名的混合。 正确的规则很简单:b $ b简单:如果任何操作数是无符号的,结果是无符号的。

这个规则简单易懂,但有时会给出

令人惊讶结果。


ISO规则是:如果任何操作数是无符号的,它会被加宽,但

结果类型取决于可能的值范围

原始无符号类型和更宽泛的类型。这个规则很复杂,很难理解,* *有时候会给出令人惊讶的
结果。 (此外,对于非位域类型,结果取决于

各种* _MAXes的相对值。特别是,USHRT_MAX为65535且INT_MAX的
实现32767

的行为与USHRT_MAX为65535和

INT_MAX为2147483647的行为不同,当使用unsigned short进行算术时。)


因为我们陷入了可怕的,几乎不可能的理由,

依赖于实现的值保留规则(我是否铺设它

有点厚?:-)),你唯一的资源是中间的

临时变量或演员。

...这可以通过在移位之前将位字段转换为unsigned int来轻松避免。但是,由此产生的程序

#include< stdio.h>

int main(void)
{
struct test {
unsigned int x:1;
} test;

test.x = 1;

printf("%lu \ n",(unsigned long) ((unsigned int)test.x<< 31));
返回0;
}
仍然使用gcc 3.3.3打印相同的值。我尝试过的所有其他编译器(包括gcc 4),打印2147483648,正如我原先预期的那样。我的
假设是否正确gcc 3在这里是错误的?
On a platform with 64-bit longs and 32-bit ints, this prints
18446744071562067968, i.e. a number that has the upper 33 bits set to 1.
This stunned me at first, but I think I have now figured out what happens:

(1) Because the bit-field is only one bit wide, all its values fit into a
signed int, so test.x is converted to one.
(2) Therefore, the result of the shift operation is a signed int too.
(3) Since the resulting value is negative on this platform, ULONG_MAX + 1 is
added to it, yielding the value mentioned above.

Is this correct?
Yes.

ANSI/ISO C has the "wrong" rules (according to me anyway :-) ) for
handling mixes of signed and unsigned. The "right" rule is very
simple: "if any operand is unsigned, the result is unsigned."
This rule is simple and easy to understand, but sometimes gives
"surprising" results.

The ISO rule is: "If any operand is unsigned, it is widened, but
the resulting type depends on the possible ranges of values of the
original unsigned type and the wider type." This rule is complicated
and hard to understand, and *still* sometimes gives surprising
results. (Moreover, the results depend on the relative values of
the various *_MAXes, for non-bitfield types. In particular,
implementations with a USHRT_MAX of 65535 and an INT_MAX of 32767
behave differently from those with a USHRT_MAX of 65535 and an
INT_MAX of 2147483647, when doing arithmetic with "unsigned short".)

Because we are stuck with the horrible, near-impossible-to-reason-about,
implementation-dependent "value preserving" rules (am I laying it
on a little thick? :-) ), your only recourses are intermediate
temporary variables or casts.
... This could then easily be avoided by casting the bit-field to
an unsigned int before the shift. However, the resulting program

#include <stdio.h>

int main(void)
{
struct test {
unsigned int x : 1;
} test;

test.x = 1;

printf("%lu\n", (unsigned long) ((unsigned int) test.x << 31));
return 0;
}

still prints the same value with gcc 3.3.3. All other compilers I have tried
(including gcc 4), print 2147483648, as I had originally expected. Is my
assumption correct that gcc 3 is wrong here?




Gcc 3.3.3在这里是错误的。


(注意,移位unsigned int31位本身至少有点风险,因为有16位int实现。)

- -

In-Real-Life:风河系统Chris Torek

美国犹他州盐湖城(40°39.22''N,111°50.29''W )+1 801 277 2603

电子邮件:忘了它http://web.torek.net/torek/index.html

阅读电子邮件就像搜索食物一样垃圾邮件,感谢垃圾邮件发送者。



Gcc 3.3.3 is wrong here.

(Note that shifting an "unsigned int" 31 bits is itself at least
a little risky, since there are 16-bit "int" implementations.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22''N, 111°50.29''W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.


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

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