在C / C ++访谈测试中,我发现了一些我没有正确回答的问题,我使用Visual C ++检查结果,希望你能帮助我理解它们:
1)
int i=-3, j=2, k=0, m;
m = ++i && ++j || ++k; // k not incremented why ???
cout << i << " " << j << " " << k << " " << m; // -2 3 0 1 why it's not -2 3 1 1 !!!
=&GT;为什么k不增加特别是在它之前有一个++?我想知道执行这种行的顺序,我无法在调试模式下执行此操作。
请你给我一个规则来评估这些表达式,其中有像++变量或变量++这样的东西谢谢
2)为什么这种比较是错误的?
float a = 5.2;
if(a == 5.2) // false
{}
当我向5.2添加浮动渲染时,它可以工作....
3)
int n()
{
static int x = 0;
return x++;
}
=&GT;我以为我们总是返回0,因为我认为编译器会将“return x ++”翻译为:return x; X ++;那么我们永远不会执行增量...
答案 0 :(得分:4)
&&
运算符优先于||
,因此将首先对其进行评估。两个术语(++i
和++j
)都有预先递增,因此首先它们分别增加到-2和3,然后它们是AND。在C ++中,0是false
,其他一切都是true
。在这种情况下,两个术语都是true
(即非零),因此&&
返回true
。现在是时候测试true || ++k
了。在这里,优化开始了:因为true || anything
总是true
,编译器甚至不测试表达式。也就是说,它不会执行它。并且k
不会递增。这就是为什么在if语句中执行某些操作时使用代码是一个非常糟糕的习惯 - 根据条件的不同,您无法确定它是否会运行。如果需要运行它,请确保它没有放在那里或者它可以被优化掉。
浮点算术很棘手 - 通常不可能代表一个数字,真正使用的数字只是一个非常接近的近似值 - 足够接近看起来它的工作原理,但是如果你去检查每一小块你注意数字不是它们的样子。默认情况下,数字被视为double
。 double
和float
虽然看起来一样,却不一样。这已经在这里讨论过:strange output in comparison of float with float literal。我真的建议您阅读其中一篇链接文章,其中一篇:"What Every Computer Scientist Should Know About Floating-Point Arithmetic"
你是对的,返回的值是0(第一次!),但是你认为该指令分为两部分,第一部分是return
,这应该导致第二部分(要跳过的增量)。不,它不会那样工作。在任何情况下都执行增量。帖子增量的工作方式如下:制作副本,增加原件,返回副本。无论什么称为后增量都会看到原始值,但增量会发生。由于x
为static
,因此将保留该值,以便下次调用函数n()
时,x
的初始值将为1.然后2,3等等。
答案 1 :(得分:3)
下次有多个问题时,请单独询问。
回答问题1:
有几件事:
&&
和||
运算符强制从左到右评估 1 ,并且都引入序列点;将评估左侧操作数并在评估右侧操作数之前应用所有副作用;
&&
和||
运算符短路 - 如果表达式的值可以从左侧操作数确定,那么右侧-hand side operand将不会被评估;
a || b
中的b
非零,则不会评估a
; a && b
中的b
为零,则不会评估a
; &&
的优先级高于||
,因此a || b && c
被解析为a || (b && c)
;
x++
评估为x
的当前值,并且副作用增加x
;
++x
评估x
的当前值加1,副作用增加x
。
所以,表达式
++i && ++j || ++k
解析为
(++i && ++j) || ++k
和评估如下:
++i
;结果是-2
,它不是零,所以:++j
;结果是3
,所以:-2
和3
都不为零,因此:++i && ++j
评估为1,所以:++k
根本没有评估。 回答问题2:
同样,有几个问题:
大多数浮点值无法正确表示 ;它们存储为近似值(您无法将无限数量的值拟合为有限数量的位);
浮点常量表达式5.2
的类型为double
,而不是float
;要使其float
,您可以使用f
后缀 - 5.2f
;
float
和double
具有不同的表示形式(double将更多位用于指数和分数),因此它们将为相同的值存储不同的近似值,这就是{{{比较没有效果。
因此,您不应使用==
来比较浮点值;通常,您将获取两个值之间的差异,并确保它小于某个epsilon值(请记住,epsilon值取决于幅度)。
回答问题3:
您将返回表达式 ==
的结果,但该表达式仍然具有递增x++
的副作用(并且副作用在结束前应用) x
声明。
<小时/> 1。 C中的大多数运算符不强制执行特定的评估顺序 - 给定
return
这样的表达式,每个a + b * c
,a
和b
可以按任何顺序评估。必须先知道c
的结果,然后才能将其添加到b * c
的结果中,但这并不代表a
或{在b
之前,{1}}必须评估
答案 2 :(得分:1)
- C和C ++使用短路逻辑。
醇>
请考虑以下事项:
bool myBool = (1 || 0+6*4);
myBool
会尽快评估。在这种情况下,它将评估为true,因为||
中的左参数为true。它立即停止评估。同样适用于&&
。这就是为什么在布尔运算符的左侧添加更可能的失败案例是惯用的。
- 这是假的,因为浮点数不能完全用二进制表示。
醇>
在这种情况下,它实际上会评估为true。但是,请考虑以下示例:
#include <iostream>
int main() {
double i = 0.1;
double total = 0.0;
for(int j = 0; j < 10000; j++) {
total+=i;
}
// total = 0.1*10000 = 1000... right?
std::cout << std::boolalpha << "total == 1000.0 ? " << (total == 1000.0) << std::endl;
return 0;
}
Here是上述程序的输出。比较浮点数和双打数是计算中的棘手问题。小心这样做。
- 因为它是静态的,所以它会在返回之前递增,并在每次调用函数时保持其静态值。
醇>
我不会太过深入,因为它在this question about lifetime of static variables中得到了很好的概括。基本上,只要程序static
存在,无论可见性如何,都会存在。