Here's the code.

#include <iostream>
using namespace std;

int a = 0;


int foo()
{
    a++;
    return a;
}

int main()
{
    if(1 || foo())
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

Result : 0 is displayed.

Change line 15 to this:

if(foo() || 1)

Result : 1 is displayed.

"Hello World" is obviously displayed in both cases. The "if" statement can only evaluate to true, regardless of order, so why bother calling foo() in the second instance? It was smart enough not to in the first instance. And does C++ REQUIRE foo() to be called in the second instance?

Recommended Answers

All 14 Replies

>> since your first operand of || was true, it skipped the foo() call in the first example.

That part I understand and expected. However, I expected the second part to also output 0. From the link, I see that both "left to right evaluation" and "short-circuiting" are mandated (thanks for the link. Good discussion on it). I was expecting a difference between RUN-time and COMPILE-time behavior though. Nothing really needs to be evaluated at all at runtime does it? It seems to me that a smart compiler should change this:

if(foo() || 1)

to this:

if(1)

and then just delete lines 15, 16, and 18 altogether as an optimization?

It has to evaluate foo() in the second case because if foo conceivably returns 0, then the second operand will have to be evaluated. I don't know if the compiler can think three steps ahead to know that that is not possible based on the values, but that might be asking a lot.

>> since your first operand of || was true, it skipped the foo() call in the first example.

That part I understand and expected. However, I expected the second part to also output 0. From the link, I see that both "left to right evaluation" and "short-circuiting" are mandated (thanks for the link. Good discussion on it). I was expecting a difference between RUN-time and COMPILE-time behavior though. Nothing really needs to be evaluated at all at runtime does it? It seems to me that a smart compiler should change this:

if(foo() || 1)

to this:

if(1)

and then just delete lines 15, 16, and 18 altogether as an optimization?

foo has a side effect, so the compiler can't just throw out the call without changing the program's behavior, and removing the call deterministically is rather difficult. However, if one side of an && or || is a constant, it's easy to ignore. So in both cases I would expect the optimizer to produce at least this:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
    if(foo())
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

The fact that a isn't qualified as volatile gives the compiler some leeway for trickery, but I wouldn't rely on it.

>> if(foo())

But Hello World should be displayed regardless of the return value of foo(), and the || 1 causes that. So you can't just toss out that or condition.

commented: Nice catch. :) +5
commented: Yep, good catch. +13

>> if(foo())

But Hello World should be displayed regardless of the return value of foo(), and the || 1 causes that. So you can't just toss out that or condition.

True. I'll blame an early morning brain fart. :D

commented: :) You're allowed one once in a while. ;) +5
commented: Regardless, I want a refund of today's ticket price ;) +7

So we went from this:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
    if(1 || foo())
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

to this:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
    cout << "Hello World\n";	
    cout << a << endl;
    return 0;
}

for case 1 and we went from this:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
    if(foo() || 1)
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

to this:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
/*    if(foo())
    {
        cout << "Hello World\n";
    }*/

    foo();
    cout << "Hello World\n";	
    cout << a << endl;
    return 0;
}

in case 2?

Let me try again, this time without the brain fart. :)

The presence of a function call in a short circuited expression is generally difficult to optimize, but the presence of a constant and a short circuit that doesn't depend on the function call helps quite a bit. if (1 || foo()) can be optimized like so:

// Conditional removed
{
    cout<<"Hello World\n";
}

Due to the short circuiting of the || operator and the fact that the left hand side is a constant, the compiler can determine what to do at compile-time. In this case, the condition is true, foo doesn't need to be called, and the body of the conditional is always executed.

On the other hand, if (foo() || 1) can be optimized like this:

// Conditional removed
foo();
{
    cout<<"Hello World\n";
}

foo still needs to be called, but its result in the conditional isn't important due to the presence of a constant as the right hand side. As you know, the result of an || test is true if either side is true, so in this case the compiler can determine at compile-time that the result is true.

If it were an && test, that would be a different matter because the result depends on the value returned by foo, and it's quite a bit harder to deterministically figure out that foo returns true with a general algorithm.

Cool. Yes, my question was more attuned to the fact that "1" is always true rather than the fact that, in this case, foo() can only return true. I would be pleased if the compiler figured out that foo() always evaluated to true, but I wasn't necessarily expecting it to.

I hadn't really thought about the need to keep the brackets (in this case it wouldn't matter, but it could in others, so I'll keep 'em).

So for case 1, we're now here:

#include <iostream>
using namespace std;

int a = 0;

int foo()
{
    a++;
    return a;
}

int main()
{
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

Can the compiler go one step further and notice that foo() will never get called and hence just delete it so we're now here?

#include <iostream>
using namespace std;

int a = 0;

int main()
{
    {
        cout << "Hello World\n";
    }
	
    cout << a << endl;
    return 0;
}

Can the compiler go one step further and notice that foo() will never get called and hence just delete it so we're now here?

No, and the reason is because foo has external linkage (a poor choice of defaults, in my opinion). It might be used in another translation unit, and introspection between translation units is pretty darn expensive. If you give foo internal linkage by qualifying it as static, then the compiler could potentially do something.

commented: Thanks. +13

Thanks. Great help. Solved. +rep to all.

Well, actually the Microsoft linkers will delete functions or data that are never called or referenced, or so their documentation tells us.

Well, actually the Microsoft linkers will delete functions or data that are never called or referenced, or so their documentation tells us.

That's probably true. I know for a fact that VS 2008 will not throw an error if you have a function declaration, but no implementation and never call the function. There have been a couple times where a piece of code made it through the linker when I didn't expect it to, and that's why.

Its not considered an error -- just an option to let the compiler optimize out unused functions and data.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.