【问题标题】:Toggling 100th bit of data type int gives unexpected results切换数据类型 int 的第 100 位会产生意想不到的结果
【发布时间】:2018-08-21 19:58:44
【问题描述】:

以下代码只要求输入一个数字num,然后输入该数字的一点tbit 来切换/反转,然后打印新数字ans

在 debian 9 上使用带有 gcc 编译器版本 6.3.0 20170516 的 Geany,当我执行以下代码时,我得到的答案 ans 为 6,当我预计编译器或运行时错误告诉我我退出时界限之类的。

使用这个版本的 gcc,sizeof(int) 返回四个字节或 32 位。当我尝试切换第 100 位时,ans=6 发生了什么?

示例输入:

Enter a number : 22
Enter the bit you want to toggle : 100

输出:

The number you entered is 22
after toggling the 100 bit
the new number is 6.`

代码:

#include <stdio.h>

int main ()
{
 int num, tbit, tool = 1, ans; 

printf(Enter a number :"); 
scanf("%d", &num); 

printf(Enter the bit you want to toggle :");
scanf("%d", &tbit);

ans = (tool<<tbit) ^ num; 

printf("The number you entered is %d after toggling the %d bit the new 
number is %d\n" , num, tbit, ans);

return 0;
}

【问题讨论】:

  • 为什么要切换没有 100 位的数据类型的第 100 位?这听起来有问题。
  • @cleblanc:我猜 OP 只是在重新输入代码时出错,因为输出似乎表明 scanf 是正确的。
  • @ChristianGibbons 只是好奇会发生什么。
  • 你不应该依赖这样奇怪的实验。 C 中有许多未定义行为的示例,因此虽然您的实验可能会显示一个结果,但另一个系统或另一个运行可能会产生另一个结果。如果您有兴趣了解更多有关事物如何工作的信息,我建议您花些时间看一下 C 标准。 open-std.org/jtc1/sc22/wg14/www/standards
  • “OP”是原始帖子或原始海报,具体取决于上下文......他在谈论你。 webopedia.com/TERM/O/op_original_poster.html

标签: c gcc int bit-manipulation toggle


【解决方案1】:

C 没有“运行时错误”之类的东西。在表达式x&lt;&lt;n 中,如果n 的值超过x 的(提升的)类型的宽度,或者如果类型已签名并且结果会溢出,则行为未定义。这意味着该语言对发生的事情没有任何要求,这可能是一些奇怪和意想不到的事情。

相关文字为6.5.7 移位运算符,¶3:

对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

【讨论】:

  • 你可以参考你的答案吗?
【解决方案2】:

根据C语言标准,行为是未定义的:

6.5.7.3:如果右操作数的值为负数或为 大于或等于提升的左操作数的宽度,则行为未定义。

在每种特定情况下发生的情况取决于硬件,因此任何依赖它的程序都是无效的。在您的情况下,硬件似乎截断了tbit 的高位,就好像代码如下:

ans = (tool<< (tbit & 0x1F)) ^ num; 

这是 X86 CPU 常见的行为:

英特尔的手册] 指出,当cnt 大于操作数大小时,结果未定义,但至少对于 32 位和 64 位数据大小,已观察到移位操作由(cnt mod n) 执行, n 是数据大小 (source)。

【讨论】:

  • 关于 x86 cpus 的注释可能会在关于 C 的问题中产生误导,因为它不需要反映编译器如何在 x86 上实现转换的任何内容。在某些情况下,&lt;&lt; 可能与mul 操作结合使用,或者使用与类型大小不同的寄存器执行(例如,移入 64 位寄存器,然后仅使用低 32 位)。或者,如果编译器静态确定移位量总是超出范围,它可能会由于未定义而将代码完全删除为不可访问。
  • @R.. 我提到这只是作为 OP 正在观察的行为的“后见之明合理化”。甚至英特尔的手册都说结果是未定义的,这可能是因为他们不希望将来做出任何特定的行为:显然,他们确切地知道他们的 CPU 对寄存器的高位做了什么。
  • x86 ISA 行为绝对不是未定义的;实际上编译器使用它来优化。参见例如godbolt.org/z/judF7w
猜你喜欢
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
相关资源
最近更新 更多