n++가 n=n+1보다 빨리 실행되는 이유는 무엇입니까?
C언어로, 왜?n++보다 빨리 실행n=n+1?
(int n=...; n++;)
(int n=...; n=n+1;)
오늘 수업에서 우리 선생님이 그 질문을 하셨습니다.(이것은 숙제가 아닙니다)
'석기시대' 컴파일러 작업을 하고 있다면 그럴 겁니다
"석기 시대"의 경우:
++n보다 빠릅니다.n++보다 빠릅니다.n=n+1
기계는 보통.increment x게다가add const to x
- 의 경우
n++, 2개의 메모리만 액세스할 수 있습니다(읽기 n, incn, 쓰기). - 의 경우
n=n+1, 3개의 메모리 액세스(읽기 n, 읽기 const, add n and const, 쓰기)가 가능합니다.
하지만 오늘의 컴파일러는 자동으로 변환됩니다.n=n+1로.++n, 그리고 그것은 당신이 상상할 수 있는 것보다 더 많은 것을 할 것입니다!!
또한 오늘날의 고장난 프로세서에서는 - "석기시대" 컴파일러의 경우에도 불구하고 - 런타임은 많은 경우에 전혀 영향을 받지 않을 수 있습니다.!!
GCC 4.4.3 for x86에서는 최적화 여부와 상관없이 정확히 동일한 어셈블리 코드로 컴파일하므로 실행에 동일한 시간이 걸립니다.조립에서 볼 수 있듯이, GCC는 단순히 변환합니다.n++안으로n=n+1, 그런 다음 하나의 명령어 추가(-O2)로 최적화합니다.
선생님의 제안에 따르면n++faster는 매우 오래된 최적화되지 않은 컴파일러에만 적용됩니다. 이 컴파일러는 인플레이스 업데이트 지침을 선택할 만큼 똑똑하지 않았습니다.n = n + 1. 이 컴파일러들은 PC 세계에서 몇 년 동안 사용되지 않았지만, 여전히 이상한 사유 임베디드 플랫폼에서 발견될 수 있습니다.
C 코드:
int n;
void nplusplus() {
n++;
}
void nplusone() {
n = n + 1;
}
출력 어셈블리(최적화 없음):
.file "test.c"
.comm n,4,4
.text
.globl nplusplus
.type nplusplus, @function
nplusplus:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.globl nplusone
.type nplusone, @function
nplusone:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusone, .-nplusone
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
출력 어셈블리(-O2 최적화 포함):
.file "test.c"
.text
.p2align 4,,15
.globl nplusplus
.type nplusplus, @function
nplusplus:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.p2align 4,,15
.globl nplusone
.type nplusone, @function
nplusone:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusone, .-nplusone
.comm n,4,4
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
컴파일러가 최적화됩니다.n + 1무일푼으로
말입니까?n = n + 1?
만약 그렇다면, 이들은 동일한 어셈블리로 컴파일됩니다. (최적화가 켜져 있고, 표현이 아닌 문장이라고 가정할 때)
누가 그러대요?당신의 컴파일러는 모든 것을 최적화해서, 정말로, 그것을 무트 포인트로 만듭니다.
현대의 컴파일러는 두 양식을 동등한 것으로 인식하고 목표 플랫폼에서 가장 잘 작동하는 형식으로 변환할 수 있어야 합니다.이 규칙에는 한 가지 예외가 있는데, 바로 부작용이 있는 가변 접근입니다.예를 들어, 만약n메모리 mapped 하드웨어 레지스터입니다. 이 레지스터를 읽고 쓰는 것은 단순히 데이터 값을 전송하는 것 이상의 일을 할 수 있습니다(예를 들어, 읽기는 인터럽트를 제거할 수 있습니다).당신은 사용할 것입니다.volatile드에 대한 하는 데 입니다.n는 와 할 수 .n++ 및 )dn = n + 1(작업 읽기, 추가 및 저장).그러나 정규 변수의 경우 컴파일러는 두 양식을 동일한 것으로 최적화해야 합니다.
그렇지 않습니다.컴파일러는 대상 아키텍처에 맞는 변경을 수행합니다.이와 같은 마이크로 최적화는 종종 불확실한 이점을 갖지만, 중요한 것은 프로그래머의 시간적 가치가 없다는 것입니다.
사실 그 이유는 사후 수정의 경우 사업자가 사전 수정의 경우와 다르게 정의되기 때문입니다.++n시키고 "에 대한 "n"를 "n"합니다를는합니다.n++는 "을 증가시켜 "n"이고마다 "n"합니다.constn"사의 ). , 구문,n = n + 1더 효율적일 것입니다.하지만 저는 위 포스터들에 동의해야 합니다.좋은 컴파일러는 사용하지 않는 반환 개체를 최적화해야 합니다.
에서 C 의 .n++식들은 정의상 다음의 부작용과 동등합니다.n = n + 1표현. 하기 때문에, 이라는 것은 , 이 는 어떠한 이 없기 에, BTWT코드가 오직 부작용에만 의존하기 때문에, 이러한 표현식이 항상 정확히 동등한 성능을 갖는다는 것이 정답이라는 것은 즉각적으로 명백합니다. (컴파일러의 최적화 설정에 관계없이, 이 문제는 어떠한 최적화와도 전혀 관련이 없기 때문입니다.)
컴파일러가 의도적으로(그리고 악의적으로) 이러한 차이를 도입하려고 할 경우에만 이러한 표현식의 성능에 대한 실질적인 차이가 발생할 수 있습니다.그러나 이 경우에는 물론 컴파일러의 작성자가 원하는 대로 어느 쪽이든 갈 수 있습니다.
소프트웨어라기보다는 하드웨어 문제에 가깝다고 생각합니다.이전 CPU에서는 n=n+1이 두 개의 메모리 위치를 필요로 하는데, 여기서 ++n은 단순히 마이크로컨트롤러 명령어입니다.하지만 현대 건축에 적용될 수 있을지는 의문입니다.
이 모든 것들은 컴파일러/프로세서/컴파일 지시에 달려있습니다.따라서 "일반적으로 더 빠른 것"이라는 가정을 하는 것은 좋은 생각이 아닙니다.
언급URL : https://stackoverflow.com/questions/2884762/why-does-n-execute-faster-than-n-n1
'programing' 카테고리의 다른 글
| SQL Server:잘못된 버전 661 첨부 (0) | 2023.10.01 |
|---|---|
| 처음 누락될 때까지 최대 날짜를 선택하는 Mysql (0) | 2023.10.01 |
| AngularJS 보간 오류 (0) | 2023.10.01 |
| PL/SQL - where-clause의 선택 조건 - 동적 sql 없이? (0) | 2023.10.01 |
| -moz- and -webkit-는 무엇입니까? (0) | 2023.10.01 |