2013-01-13 93 views
1

我正在阅读关于SO的this问题。在阅读第一个答案后,我无法理解-5 >> 1 = -3的原因。我也围绕它做了一些调整。划分和移位之间的区别

您也可以看到代码并输出here。 这里是我做过什么:

#include<stdio.h> 

int main(){ 

printf("5/2 = %d\n",5/2); 
printf("5 >> 1 = %d\n",5 >> 1); 
printf("5/2 = %lf\n",5/2); 
printf("5 >> 1 = %f\n",5 >> 1); 
printf("-5/2 = %d\n",-5/2); 
printf("-5 >> 1 = %d\n",-5 >> 1); 
printf("-5/2 = %f\n",-5/2); 
printf("-5 >> 1 = %f\n",-5 >> 1); 

return 0; 
} 

输出:

5/2 = 2 
5 >> 1 = 2 
5/2 = 2.168831 
5 >> 1 = 2.168831 
-5/2 = -2 
-5 >> 1 = -3 
-5/2 = 2.168833 
-5 >> 1 = 2.168833 

我无法理解5/2 == 2.168831, 5 >> 2 == 2.168831, 5 >> 1 == -3

为什么发生这种情况?(这可能是答案是非常基本的,我错过了一些基本的东西,所以请指导我)。

+3

C11最终草案,第6.5.7节:“ * E1 >> E2的结果是E1向右移位的E2位置......如果E1有符号类型和负值,则结果值为实现定义*“C11最终草案,§7.21.6.1: “*如果转换规范无效,则行为是未定义的。如果任何参数不是相应转换规范的正确类型,则行为未定义。*” – DCoder

回答

3

你看你做的结果的原因是:

当你传递一个int说法,但使用的printf说明符double(记住,float在这种情况下转换为double),那么大多数C语言实现按照它们通常的int参数传递int参数给变量函数(一种接受不同参数类型的函数),但printf例程将机器状态解释为好像它已通过double参数一样传递参数int,如下所述。 (这不一定总是发生;一旦你离开了C标准定义的行为,C实现可能会做其他事情,尤其是与优化器之间可能存在复杂的交互,这会导致令人惊讶的结果。 )

每个计算平台都有一些关于如何传递参数的规则。一个平台可能会将所有参数指定为从右向左推送到堆栈,并且每个参数都只能使用尽可能多的字节。另一个平台可能会指定从左到右将参数压入堆栈,或者将参数填充到四个字节的下一个倍数,以使堆栈保持良好对齐。许多现代平台都指定在一般寄存器中传递特定大小的整数参数,浮点参数在浮点寄存器中传递,其他参数在堆栈中传递。

printf看到%f并寻找double说法,但你通过一个int,是什么printf找到?如果此平台将两个参数压入堆栈,则printf会找到您的int的位,但它会将这些位解释为double。这导致printf打印由您的int确定的值,但它与您的int没有明显关系,因为这些位在编码intdouble的编码中有完全不同的含义。

如果这个平台把一个int参数在同一个地方,但在另一个地方double参数,那么printf发现一些比特什么都没有做与你int说法。它们只是偶然发生的位,例如,参数应该是的浮点寄存器。这些位仅仅是以前工作的剩余部分。您获得的价值将基本上是随机的,相对于您通过的int。您也可以混合使用,printf通过将四个字节的int与四个字节的其他任何附近位置一起传送,寻找double的八个字节。

当您多次运行该程序时,您将经常看到打印的相同值。这种情况有两个原因。首先,电脑是机械的。它们以很大程度上确定性的方式运行,所以它们一次又一次地做同样的事情,即使这些事情并不是按照你使用它们的方式来设计的。其次,操作系统在启动时传递给程序的环境在每次启动程序时都基本相同。其大部分内存要么被清除,要么从程序文件初始化。一些内存或其他程序状态是从计算机中的其他环境初始化的。该数据可能与程序的运行不同。例如,当前时间显然会随着运行而变化。您的命令历史记录也是如此,以及命令shell放置在其环境变量中的值。有时多次运行程序会产生不同的结果。

当您使用其行为未由某些规范(可能是C规范,编译器规范,机器和操作系统规范或其他文档)定义的代码时,则不能依赖该代码的行为。 (可以依赖由C编译器指定的特定C编译器编译的代码的行为,尽管C标准没有完全指定它。)

9

-5/2结果是int,而不是一个floatdouble。然而你的格式说明符是%f,所以你的int得到解释为作为float,这是没有意义的,因此是不稳定的值。你在做什么叫未定义的行为:任何事情都可能发生。

+0

但是,为什么此错误始终保持一致。我不明白这个特殊的价值会如何。把'%f'放在一边是故意的 –

+2

它*发生*是。这是不确定的行为:任何事情都可能发生。试图从结果中理解是没有意义的。例如,在我的机器上,我得到'0'而不是'2.168831'。 –

+1

说明没有必要尝试理解结果是不正确的。理解计算机为什么会这样运行并不会帮助人们理解C,但它可以帮助理解计算机,传递参数的低级机制以及如何实现编译器。这些知识非常重要,对于努力理解计算复杂性的学生来说,这些知识可能会有所启发。没有理由要求人们只将C学习为抽象概念,不要学习如何构造抽象概念。 –