【问题标题】:Bitwise shift left and right in the same statement在同一个语句中按位左移和右移
【发布时间】:2015-09-28 21:40:55
【问题描述】:

char c2=i1<<8>>24; 是有效的 C 语法吗? (其中i1 是无符号整数)此外,它会产生将i1 分别向左移动8 位和向右移动24 位的结果吗?我正在解压以前存储在i1 中的一个字符以及其他三个字符。代码如下:

unsigned char b3 = 202;
unsigned char b2 = 254;
unsigned char b1 = 186;
unsigned char b0 = 190;
...


unsigned int i1=202;
i1=i1<<8;
i1=i1+254;
i1=i1<<8;
i1=i1+186;
i1=i1<<8;
i1=i1+190;
...

char c1=i1>>24;
char c2=i1<<8>>24;

【问题讨论】:

  • 您的编辑很有用!您实际上可以发布将 4 个chars 组合成int 的代码吗?那里可能潜伏着一个微妙的错误。
  • @chqrlie 按要求修改。
  • 约翰·布林格中了靶心!您绝对应该将c1c2 等声明为unsigned char。您正在处理超过 127 的字节值,您要求使用可能默认签名的 char 类型来处理它们。
  • 他的观点很好!谢谢@John Bollinger
  • 即使将202 存储到char 中没有任何问题,你仍然不能指望c1 == b3c1 == 202,因为char 可以是signed 或@ 987654338@ 取决于编译器设置和平台默认值。

标签: c bit-manipulation


【解决方案1】:

语法很好(虽然难以阅读),它会被解析为c2 = (i1 &lt;&lt; 8) &gt;&gt; 24

所以它将左移i1 8 个位置,从而将最左边的 8 位移出左侧边缘,然后将结果右移 24 个位置,从而将最右侧的 16 位移出右侧边缘。如果那是你想要的,那么你很好。我会使用括号使其更具可读性。

如果您只是要将其转换为char,那么您为什么觉得需要删除高位位并不明显(尽管确实可能存在int 和@ 987654325@ 大小相同。)

此外,正如 John Bollinger 所指出的,最终结果可能大于 char 的大小,这在 char 是有符号类型的常见情况下没有得到很好的定义。 (即使unsigned int 是 32 位也是如此,因为从技术上讲,您不能将大于 127 的值分配给 8 位有符号字符。)

【讨论】:

  • 由于整个语句将结果分配给 char 类型的变量,因此可能值得一提的是,如果 char 是有符号类型并且分配给它的表达式大于CHAR_MAX
  • @John Bollinger:不完全是未定义的行为,但绝对值得一提:C11 6.3.1.3 p3 否则,新类型已签名且无法在其中表示值;结果要么是实现定义的,要么是产生实现定义的信号。
  • @chqrlie,是的,我很马虎。实现定义!=未定义。不过,无论哪种方式,都最好避免。
  • @JohnBollinger:chqrlie 说了什么,我要补充一点,有很多 程序假设char* p = buf; int c; while ((c = getchar()) != EOF) *p++ = c; 是有效的。 (我写过类似的东西,我敢打赌你也写过 :))(显然有适当的缓冲区溢出检查)
  • 还有一个证据表明,char 唯一一致的选项是默认情况下是 unsigned(即:gcc -funsigned-char
【解决方案2】:

是的,这是一个有效的语法。对于有符号的int i1,它也是一种有效的语法,在这种情况下,您可以使用所选位置的位来填充值的“上部”。

【讨论】:

  • 如果值为负数,则右移有符号整数是实现定义的。所以你不能依赖可移植代码中的符号扩展。
【解决方案3】:

正如其他人所指出的,它是有效的语法。您可以通过以下方式实现我认为更易于理解和便携的效果:

unsigned char c2 = (i1 & 0xff0000) >> 16;

【讨论】:

  • 这样实际上会更容易理解:unsigned char c2 = (i1 &gt;&gt; 16) &amp; 0xff;
  • @chqrlie 我无法决定哪个更容易理解,我认为选择一个更容易理解。
  • "portably" 已准备就绪,因为代码依赖于 32+ 位 unsigned int,因为 C 规范仅要求 16 位或更多位。
猜你喜欢
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多