I ++ and ++ i efficiency difference

zhaozj2021-02-08  471

A question that countless people discussed, and finally saw a person to be fully clear today. The following post is Shornmao (dead cat), I just help him post it, I hope that the cat is not angry with me.

-----------------------

First, declare that simple comparison prefix self-incremental operators and suffixes of efficiency from the resemble operator are one-sided because there are many factors that affect this question.

First consider the situation of built-in data type:

If the result of the self-increasing operational expression is not used, just simply use it for increasing one operand, the answer is clear, the prefix method and the suffix method do not have any difference, the compiler should be the same, it is difficult Imagine what compiler can be made to make any difference between the two.

Test C source code as follows:

//test1.cpp

Void test ()

{

INT i = 0;

i ;

i;

}

The intermediate code compilation of GNU C / C 2 is as follows:

.file "test1.cpp"

GCC2_Compiled .:

___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test__fv

.def _test__fv ;.scl 2; .type 32; .ndef

_Test__fv:

Pushl% EBP

MOVL% ESP,% EBP

SUBL $ 24,% ESP

MOVL $ 0, -4 (% EBP); i = 0

INCL-4 (% EBP); i

INCL-4 (% EBP); i

JMP L3

JMP L2

.p2align 4,, 7

L3:

L2:

Leave

RET

Obviously, no matter whether it is i or i is just an INCL directive.

If the result of the expression is used, then the situation is slightly more complicated.

Test C source code as follows:

//test2.cpp

Void test ()

{

INT I = 0, A, B;

A = i ;

B = i;

}

The intermediate code compilation of GNU C / C 2 is as follows:

.file "test2.cpp"

GCC2_Compiled .:

___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test__fv

.def _test__fv ;.scl 2; .type 32; .ndef

_Test__fv:

Pushl% EBP

MOVL% ESP,% EBP

SUBL $ 24,% ESP

MOVL $ 0, -4 (% EBP); i = 0

MOVL-4 (% EBP),% EAX; I -> AX

MOVL% EAX, -8 (% EBP); AX -> A (a = i)

INCL-4 (% EBP); i

INCL-4 (% EBP); i

MOVL-4 (% EBP),% EAX; I -> AX

MOVL% EAX, -12 (% EBP); AX -> b (b = i)

JMP L3

JMP L2

.p2align 4,, 7

L3:

L2:

Leave

RET

Is there a difference? Obviously, it is not, the same INCL directive, plus two MOVL instructions Borrow the EAX register copy call call.

Let us add the compiler to optimize, and the compiletable assembly code is as follows:

.file "test2.cpp"

GCC2_Compiled.:___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test__fv

.def _test__fv ;.scl 2; .type 32; .ndef

_Test__fv:

Pushl% EBP

MOVL% ESP,% EBP

Leave

RET

Ok, optimized overflow, because I, A, B have not been used, so simply all optimized, and the result is an empty correspondence that does nothing.

So, let's add a little code to the results of A and B, so that the results of I cannot be ignored, the C source code is as follows:

//test3.cpp

Int test ()

{

INT I = 0, A, B;

A = i ;

B = i;

RETURN A B;

}

At this time, the assembly code is as follows:

.file "test3.cpp"

GCC2_Compiled .:

___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test__fv

.def _test__fv ;.scl 2; .type 32; .ndef

_Test__fv:

Pushl% EBP

MOVL% ESP,% EBP

MOVL $ 2,% EAX

Leave

RET

You still haven't thought about it, the answer is just the compiler calculates the return value, constant-unwinding is started, and it has become a direct return constant result.

How to do? We turn I to parameters to avoid this expected result, C source code as follows:

//test4.cpp

Int Test1 (INT I)

{

INT A = i ;

Return A;

}

Int test2 (INT i)

{

INT A = i;

Return A;

}

Ok, very hard, finally got a different assembly code:

.file "test4.cpp"

GCC2_Compiled .:

___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test1__fi

.def _test1__fi; .scl 2; .type 32; .ndef

_TEST1__FI:

Pushl% EBP

MOVL% ESP,% EBP

MOVL 8 (% EBP),% EAX

Leave

RET

.align 4

.globl _test2__fi

.def _test2__fi; .scl 2; .Type 32; .endef

_Test2__fi:

Pushl% EBP

MOVL% ESP,% EBP

MOVL 8 (% EBP),% EAX

INCL% EAX

Leave

RET

In contrast, i has added a compilation instructionin, but i is not, this is the charm of the compiler optimization.

Because no matter what is increased, it does not affect A's value, and the function returns only the value of i, so I's self-incremental operation does not have to be done.

So, in order to objectively, we change the I parameters to the reference delivery, the C source code is as follows;

//test5.cpp

Int Test1 (INT & I)

{

INT A = i ;

Return A;

}

Int test2 (int & i)

{

INT A = i;

Return A;

}

This time the result joins the calculation of the pointer, slightly more complex:

.file "test5.cpp"

GCC2_Compiled .:

___gnu_compiled_cplusplus:

.Text

.align 4

.globl _test1__fri

.def _test1__fri; .scl 2; .Type 32; .endef

_TEST1__FRI:

Pushl% EBP

MOVL% ESP,% EBP

MOVL 8 (% EBP),% EAX

MOVL (% EAX),% EDX

INCL (% EAX)

MOVL% EDX,% EAX

Leave

RET

.align 4

.globl _test2__fri

.def _test2__fri; .scl 2; .TYPE 32; .endef

_Test2__fri:

Pushl% EBP

MOVL% ESP,% EBP

MOVL 8 (% EBP),% EAX

MOVL (% EAX),% EDX

LEAL 1 (% EDX),% ECX

MOVL% ECX, (% EAX)

MOVL% ECX,% EAX

Leave

RET

Surprised? Still a = i code is more efficient, don't know what this will make you think. Anyway, I conclude that I and i is very bad for the built-in data type, and it is related to the compiler. It is really not necessary to care about this problem.

Finally, let us return to the starting point, saying that the custom data type (mainly the class) said, there is no need to do a lot of assembly code, I know why people will follow people.

Since the prefix type can return the reference to the object, the suffix type must return the value of the object, so that the larger copy overhead has caused a large object, causing the efficiency to decrease, and avoid use as much as possible The suffix is ​​true unless the suffix is ​​really required from the behavior.

This is also the original text mentioned in More Effective C / Term 7, and the user should use the prefix-type / decrease in the use of prefix-based, because he is more natural good.

At the same time, in order to ensure that the prefix and suffix are consistent with the implementation of the semantics of the increment / decrement, the general principles of design are the suffix-based implementation, so that the suffix type often has more functions, this may also be a need. In contanced efficiency factors, it is a bit slightly slightly.

Reesence a little further narrative about this issue, it can be obtained in the clause 7 of Scott Mayer << More Effective C >>, approximately on the P31-34 of the original book.

转载请注明原文地址:https://www.9cbs.com/read-633.html

New Post(0)