请考虑以下代码:
int f(int a, int b, int *c) {
*c = a + b;
return *c > 0;
}
void check(int a, int b) {
int c;
if(f(a, b, &c) && c < 10) {
puts("sum is in range [1, 9]");
}
}
如果评估&&
的第二部分,c
是否保证保留函数调用f(a, b, &c)
赋予它的值?此行为是否从C更改为C ++?
答案 0 :(得分:7)
如果出现控制评估顺序的序列点,则是安全的。
// bad: evaluation order of f() and (c < 10) is not specified by C
if(f(a, b, &c) & c < 10) {
// OK, left half of && must occur first.
if(f(a, b, &c) && c < 10) {
使用简单的&&
表达式,没有C,C ++差异。使用C / C ++评估左侧,如果左侧不是假,则评估右侧。
在C ++中,这一点上的行为更复杂,&&
运算符可以重载,然后&&
的两边都会被评估。
答案 1 :(得分:4)
是的,表达式将从左到右进行评估,c
的值将相应更新。执行程序将进入函数,函数中执行的任何操作都将在c < 10
之前执行。
此行为不应从C
更改为C++
答案 2 :(得分:3)
分配给它的值
c
保证保留函数调用f(a, b, &c)
是。这在[expr.log.and]中非常清楚地表达出来:
&&
运算符组从左到右。操作数都在上下文中转换为bool
(第4条)。 如果两个操作数分别为true
和true
,则结果为false
。与&
不同,&&
保证从左到右 评估:如果第一个操作数为false
,则不评估第二个操作数。结果是
bool
。 如果计算第二个表达式,则每个值计算和副作用都相关联 第一个表达式在每个值计算和与之相关的副作用之前进行排序 第二个表达。
答案 3 :(得分:0)
if(f(a, b, &c) && c < 10)
运算符强制从左到右评估并引入一个序列点(函数调用本身也是如此);在决定是否需要对RHS进行评估之前,对LHS进行全面评估(并应用所有副作用)。
因此,c < 10
将按预期工作;如果对c
进行评估,则会使用函数f
将值写入if ( f( a, b, &c ) )
{
if ( c < 10 )
{
// do stuff
}
}
。
话虽如此,这并不是很好的风格。仅仅因为C和C ++允许某些结构并不意味着使用它们是个好主意。任何人都需要维护您的代码,可能会感谢您将其编写为
COPY temp_table FROM loread(lo_open((SELECT csv_file_oid FROM files_table WHERE liberacao_base_id = 104), 262144), 1000000) WITH DELIMITER ; CSV HEADER;
代替。
是的,页面上需要更多空间,但逻辑更明显。
答案 4 :(得分:-1)
恕我直言,你展示的代码根本不行。让我稍微改变你的例子中的函数:
int f(int a, int b, int& c) {
c = a + b;
return c > 0;
}
现在假设您只获得以下代码:
void check(int a, int b) {
int a = 3;
int b = 10;
int c = 7;
std::cout << c << std::endl;
if(f(a, b, c) || c < 10) {
std::cout << "moo" << std::endl;
}
}
期望它打印什么?
当然,一旦你知道f
,就没有问题,而如果你写了
/*...*/
int result = f(a,b,c);
std::cout << c << std::endl;
if(result || c < 10) {
std::cout << "moo" << std::endl;
}
即使您不了解f
,代码也更容易阅读(和调试)。