如果在一个表达式中不同时使用左移和右移,为什么会有所不同? [英] Why does it make a difference if left and right shift are used together in one expression or not?

查看:118
本文介绍了如果在一个表达式中不同时使用左移和右移,为什么会有所不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

unsigned char x = 255;
printf("%x\n", x); // ff

unsigned char tmp = x << 7;
unsigned char y = tmp >> 7;
printf("%x\n", y); // 1

unsigned char z = (x << 7) >> 7;
printf("%x\n", z); // ff

我希望yz相同.但是,根据是否使用中间变量,它们会有所不同.知道为什么会这样很有趣.

I would have expected y and z to be the same. But they differ depending on whether a intermediary variable is used. It would be interesting to know why this is the case.

推荐答案

这个小测试实际上比它看起来更微妙,因为行为是由实现定义的:

This little test is actually more subtle than it looks as the behavior is implementation defined:

  • unsigned char x = 255;在这里没有歧义,x是值为255unsigned char,保证类型unsigned char具有足够的范围来存储255.

  • unsigned char x = 255; no ambiguity here, x is an unsigned char with value 255, type unsigned char is guaranteed to have enough range to store 255.

printf("%x\n", x);这会在标准输出上生成ff,但是写printf("%hhx\n", x);会更干净,因为printf期望将unsigned int用于转换%x,而x不是.传递x实际上可能会传递intunsigned int参数.

printf("%x\n", x); This produces ff on standard output but it would be cleaner to write printf("%hhx\n", x); as printf expects an unsigned int for conversion %x, which x is not. Passing x might actually pass an int or an unsigned int argument.

unsigned char tmp = x << 7;为了评估表达式x << 7,作为unsigned charx首先要接受C标准 6.3.3.1 中定义的整型促销. strong>:如果int可以表示原始类型的所有值(受位字段的宽度限制),则该值将转换为int;否则,该值将转换为int.否则,它将转换为unsigned int.这些称为整数促销.

unsigned char tmp = x << 7; To evaluate the expression x << 7, x being an unsigned char first undergoes the integer promotions defined in the C Standard 6.3.3.1: If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.

因此,如果unsigned char中的值位数小于或等于int(当前最常见的情况是8 vs 31),则首先将x提升为具有相同值的int值,然后向左移动7个位置.结果0x7f80确保适合int类型,因此行为已得到很好的定义,并将此值转换为类型unsigned char将有效地截断该值的高阶位.如果类型unsigned char具有8位,则值将为128(0x80),但是如果类型unsigned char具有更多位,则tmp中的值可以为0x1800x3800xf800x1f800x3f80甚至是0x7f80.

So if the number of value bits in unsigned char is smaller or equal to that of int (the most common case currently being 8 vs 31), x is first promoted to an int with the same value, which is then shifted left by 7 positions. The result, 0x7f80, is guaranteed to fit in the int type, so the behavior is well defined and converting this value to type unsigned char will effectively truncate the high order bits of the value. If type unsigned char has 8 bits, the value will be 128 (0x80), but if type unsigned char has more bits, the value in tmp can be 0x180, 0x380, 0x780, 0xf80, 0x1f80, 0x3f80 or even 0x7f80.

如果类型unsigned char大于int,这可能发生在少数系统中,其中sizeof(int) == 1x被提升为unsigned int,并且对该类型执行左移.值是0x7f80U,可以保证适合unsigned int类型,并且将其存储到tmp实际上不会丢失任何信息,因为类型unsigned char具有与unsigned int相同的大小.因此,在这种情况下,tmp的值将为0x7f80.

If type unsigned char is larger than int, which can occur on rare systems where sizeof(int) == 1, x is promoted to unsigned int and the left shift is performed on this type. The value is 0x7f80U, which is guaranteed to fit in type unsigned int and storing that to tmp does not actually lose any information since type unsigned char has the same size as unsigned int. So tmp would have the value 0x7f80 in this case.

unsigned char y = tmp >> 7;评估与上述步骤相同,根据系统将tmp提升为intunsigned int,并保留其值,并将该值右移7个位置,由于7小于类型的宽度(intunsigned int)并且值是正数,因此已完全定义.根据unsigned char类型的位数,存储在y中的值可以是137153163127255,最常见的体系结构将是y == 1.

unsigned char y = tmp >> 7; The evaluation proceeds the same as above, tmp is promoted to int or unsigned int depending on the system, which preserves its value, and this value is shifted right by 7 positions, which is fully defined because 7 is less than the width of the type (int or unsigned int) and the value is positive. Depending on the number of bits of type unsigned char, the value stored in y can be 1, 3, 7, 15, 31, 63, 127 or 255, the most common architecture will have y == 1.

printf("%x\n", y);,最好写printf("%hhx\n", y);,输出可能是1(最常见的情况)或37f1f3f7fff,具体取决于unsigned char类型的值位数.

printf("%x\n", y); again, it would be better t write printf("%hhx\n", y); and the output may be 1 (most common case) or 3, 7, f, 1f, 3f, 7f or ff depending on the number of value bits in type unsigned char.

unsigned char z = (x << 7) >> 7;如上所述,在x上执行整数提升,然后将值(255)左移7位,作为intunsigned int,始终产生,然后右移7个位置,最终值为0xff.此行为已完全定义.

unsigned char z = (x << 7) >> 7; The integer promotion is performed on x as described above, the value (255) is then shifted left 7 bits as an int or an unsigned int, always producing 0x7f80 and then right shifted by 7 positions, with a final value of 0xff. This behavior is fully defined.

printf("%x\n", z);再一次,格式字符串应为printf("%hhx\n", z);,输出将始终为ff.

printf("%x\n", z); Once more, the format string should be printf("%hhx\n", z); and the output would always be ff.

如今,字节多于8位的系统变得越来越稀少,但是某些嵌入式处理器(例如专用DSP)仍然可以做到这一点.为%x转换说明符传递unsigned char时,将导致一个错误的系统失败,但是使用%hhx或更方便地编写printf("%x\n", (unsigned)z);

Systems where bytes have more than 8 bits are becoming rare these days, but some embedded processors, such as specialized DSPs still do that. It would take a perverse system to fail when passed an unsigned char for a %x conversion specifier, but it is cleaner to either use %hhx or more portably write printf("%x\n", (unsigned)z);

在此示例中,将移动8而不是7会更加人为设计.在具有16位int和8位char的系统上,它将具有未定义的行为.

Shifting by 8 instead of 7 in this example would be even more contrived. It would have undefined behavior on systems with 16-bit int and 8-bit char.

这篇关于如果在一个表达式中不同时使用左移和右移,为什么会有所不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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