If Statement Versus If Statement

closed account (zb0S216C)
1
2
3
4
5
6
7
8
9
10
void Function(int *A, int *B)
{
    // Style A:
    if(!A) // Handle condition...
    if(!B) // Handle condition...

    // Style B:
    if((!A) && (!B))
        // Handle condition...
}

1) Is there a difference in amount of control branches generated?
2) From a performance perspective, which is faster?

Since I'm already here, I'll ask a question that has always bugged me: In the following if statement, will the compiler generate a stack-frame? Or is a stack-frame generated irrespective of the statements that follow?

1
2
3
4
int A(0), B(1);
// ...
if(A < B)
    A = B;

Wouldn't pushing a new stack-frame be a pointless operation in this case? Because I think that such an operation would consume more time than the assignment itself.

Thanks :)

Wazzak
In your first question, those are just completely different things.

To have to equal versions, you'd do this:
1
2
3
4
5
if (!A && !B) // Stuff
<or>
if (!A) 
    if (!B)
         // Stuff 


Checking the generated assembler code, I'd conclude that both versions are completely the same:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Test code
int main()
{
	int A, B;
	std::cin >> A;
	std::cin >> B;
	if (A < 10 && B < 10) {
		std::cout << "test1\n";
	}
	if (A < 10) {
		if (B < 10) {
			std::cout << "test2";
		}
	}
	return 0;
}

	if (A < 10 && B < 10) {
012114C0  cmp         dword ptr [A],0Ah  
012114C4  jge         main+6Fh (12114DFh)  
012114C6  cmp         dword ptr [B],0Ah  
012114CA  jge         main+6Fh (12114DFh)  
		std::cout << "test1\n";
<snipped>
	}

	if (A < 10) {
012114DF  cmp         dword ptr [A],0Ah  
012114E3  jge         main+8Eh (12114FEh)  
		if (B < 10) {
012114E5  cmp         dword ptr [B],0Ah  
012114E9  jge         main+8Eh (12114FEh)  
			std::cout << "test2";
<snipped>

I'm not entirely convinced that's the proper way to compare these things, but I'm quite sure compilers are smart enough to see that both "versions" are equal.
yes compilers wont care which way its done but you should group if statement tests together if you want the code it is going to execute to execute under similar condtions ie all are || or &&
closed account (zb0S216C)
Thanks for your reply, Gaminic. The assembly output seems pretty convincing. Though, it appears
if((!A) && (!B)) is more efficient (1 stack-frame by the looks of it).

Aramil, of Elixia, thanks for your advice. I'll remember that for next time :)

Thanks for your input, lads :)

Wazzak
Last edited on
Could you explain how you reached that conclusion?
closed account (zb0S216C)
if (A < 10 && B < 10) {
012114C0  cmp         dword ptr [A],0Ah  
012114C4  jge         main+6Fh (12114DFh)  
012114C6  cmp         dword ptr [B],0Ah  
012114CA  jge         main+6Fh (12114DFh)  
		std::cout << "test1\n";
<snipped>
	}

When a pair of braces follows an if statement, it means a new stack-frame, right? Well, in the above assembly code, only 1 stack-frame is pushed onto the stack. This means the CPU only has to jump once, not twice. Now look this this assembly code:

if (A < 10) {
012114DF  cmp         dword ptr [A],0Ah  
012114E3  jge         main+8Eh (12114FEh)  
		if (B < 10) {
012114E5  cmp         dword ptr [B],0Ah  
012114E9  jge         main+8Eh (12114FEh)  
			std::cout << "test2";

There's two opening braces here, which means 2 stack-frames are pushed onto the stack. Before the second cmp and jge instructions are executed, a new stack-frame must be created, then the CPU jumps to the start of the new stack-frame. This, of course, consumes clock-cycles. However, in the first block of assembly code, all instructions are grouped together without any form of interruption.

Though, I'm not 100% about this.

Wazzak
I think you are confusing stack frames with scope. Scoping of variables is handled at compile time. If initializing takes place, constructors are called, or destructors called, then there is obviously overhead, but this would exist regardless.

Stack frames are managed during execution, and from the second assembly listing above you can see that nothing other than the comparison and jump takes place between the first opening bracket and the second.
1
2
3
4
5
6
7
8
9
10
11
12
13
void Function(int *A, int *B)
{
    // Style A:
    if(!A) 
         if(!B) { /* Handle condition... */ }

    // Style B:
    if((!A) && (!B)) { /* Handle condition... */ }
        
    // Style C:
    if( A || B ) ; // nothing to do
    else { /* Handle condition... */ }   
}


I tend to prefer Style C
Topic archived. No new replies allowed.