C/C++의 엔드리스 루프
엔드리스 루프를 실행할 수 있는 몇 가지 방법이 있습니다.다음으로 몇 가지를 선택하겠습니다.
for(;;) {}
while(1) {}
/while(true) {}
do {} while(1)
/do {} while(true)
어떤 양식을 선택해야 합니까?그리고 현대의 컴파일러는 중간과 마지막 문장의 차이를 만드는가, 아니면 끝없는 루프라는 것을 깨닫고 체크 부분을 완전히 건너뛰는가?
편집: 말씀드린 대로 잊어버렸습니다.goto
명령어로서 전혀 마음에 들지 않기 때문에, 이 조작을 실시했습니다.
편집 2: kernel.org에서 가져온 최신 버전으로 GREP를 만들었습니다.(최소한 커널 내에서는) 시간이 지나도 큰 변화는 없는 것 같습니다.
이 질문을 하는 것의 문제는 단순히 "이것이 더 좋다"는 주관적인 답변을 너무 많이 받는다는 것입니다.그런 무의미한 발언을 하는 대신, 개인적인 의견보다는 사실과 참고 자료로 이 질문에 답하도록 노력하겠습니다.
경험상, 일반적으로 사용되지 않는 do-while 대안(및 goto)을 제외하는 것부터 시작할 수 있을 것입니다.전문가들에 의해 작성된 실제 제작 코드로 본 적이 없는 것 같습니다.
그while(1)
,while(true)
그리고.for(;;)
는 실제 코드에 일반적으로 존재하는 3가지 버전입니다.물론 완전히 동일하며, 결과적으로 동일한 기계 코드가 생성됩니다.
for(;;)
이것은 영원한 루프의 원초적이고 표준적인 예입니다.Kernighan과 Ritchie의 고대 C 성경 The C Programming Language에서 우리는 다음과 같이 읽을 수 있다.
K&R 제2판 3.5:
for (;;) { ... }
는, 아마 브레이크나 리턴등의 다른 방법으로 끊어지는 「불량」루프입니다.사용 기간 중 또는 용도 여부는 대부분 개인 취향의 문제입니다.
오랫동안(그러나 영원히) 이 책은 C언어의 규범이자 정의로 여겨졌다.K&R이 예를 보여주기로 결정한 이후
for(;;)
적어도 1990년 C 표준화까지는 이것이 가장 올바른 형태로 간주되었을 것이다.하지만 이미 K&R 스스로 선호도 문제라고 밝혔다.
그리고 오늘날 K&R은 표준적인 C 레퍼런스로 사용하기에는 매우 의심스러운 정보원입니다.C99나 C11을 다루지 않고 여러 번 구식일 뿐만 아니라 현대 C 프로그래밍에서 종종 나쁘거나 노골적으로 위험하다고 여겨지는 프로그래밍 관행을 설파한다.
그러나 K&R이 의심스러운 출처임에도 불구하고, 이러한 역사적 측면은 가장 강력한 주장으로 보인다.
for(;;)
.에 대한 의론
for(;;)
루프는 다소 모호하고 읽을 수 없다는 것입니다.코드의 기능을 이해하려면 표준에서 다음 규칙을 알아야 합니다.ISO 9899:2011 6.8.5.3:
for ( clause-1 ; expression-2 ; expression-3 ) statement
/--/
절-1과 식-3은 모두 생략할 수 있습니다.생략된 식-2는 0이 아닌 상수로 대체됩니다.
이 표준문헌을 바탕으로 하면 for loop의 첫 번째 부분과 세 번째 부분은 생략했을 때 두 번째 부분과 다르게 취급되기 때문에 불분명할 뿐만 아니라 미묘하다는 것에 대부분이 동의할 것이라고 생각합니다.
while(1)
이것은 아마도 보다 읽기 쉬운 형식일 것이다.
for(;;)
단, C가 0이 아닌 모든 식을 부울 논리 참으로 취급한다는 것은 잘 알려져 있지만 불분명한 또 다른 규칙에 의존합니다.C프로그래머라면 누구나 알고 있기 때문에 큰 문제는 아닐 것입니다.이 양식에는 한 가지 크고 실용적인 문제가 있습니다. 즉, 컴파일러가 경고하는 경향이 있습니다. "조건은 항상 참" 또는 이와 유사합니다.이것은 다양한 버그를 발견하는 데 도움이 되기 때문에 비활성화 시키고 싶지 않은 좋은 경고입니다.예를 들어 다음과 같은 버그가 있습니다.
while(i = 1)
프로그래머가 쓰려고 했을 때while(i == 1)
.또한 외부 정적 코드 분석기는 "condition is always true"에 대해 불평할 수 있습니다.
while(true)
만들기 위해서
while(1)
보다 읽기 쉽고, 일부 용도while(true)
대신.프로그래머들 사이에서는 이것이 가장 읽기 쉬운 형태라는 데 의견이 일치한 것 같습니다.그러나 이 양식에는 다음과 같은 문제가 있습니다.
while(1)
상기와 같이 "condition is always true" 경고입니다.C의 경우 이 형식은 매크로를 사용한다는 또 다른 단점이 있습니다.
true
stdbool.h 에서.따라서 컴파일을 하려면 헤더 파일을 포함해야 합니다.이 파일은 불편하거나 불편하지 않을 수 있습니다.C++에서는 문제가 되지 않습니다.bool
원시 데이터 유형으로 존재하며true
는 언어 키워드입니다.이 폼의 또 다른 단점은 C99 bool 타입을 사용하고 있다는 것입니다.C99 bool 타입은 최신 컴파일러에서만 사용할 수 있으며 하위 호환성은 없습니다.다시 말씀드리지만, 이것은 C++가 아닌 C에서만 발생합니다.
그럼 어떤 양식을 사용할까요?둘 다 완벽해 보이지 않는다.그것은 K&R이 암흑기에 이미 말했듯이 개인적인 취향의 문제이다.
저는 개인적으로 항상for(;;)
다른 폼에서 자주 발생하는 컴파일러/컴파일러 경고를 피하기 위해서입니다.하지만 이 때문에 더 중요한 것은 다음과 같습니다.
C초보자도 알고 있다면for(;;)
영원한 루프를 의미합니다. 그럼 코드를 더 쉽게 읽을 수 있게 하려고 하는 사람은 누구입니까?
결론부터 말하면 그런 것 같아요.프로그래밍 언어의 기본적인 부분조차 모르는 비프로그래머에게 소스 코드를 읽을 수 있게 하려고 한다면, 그것은 시간 낭비일 뿐입니다.그들은 당신의 코드를 읽으면 안됩니다.
그리고 당신의 코드를 읽어야 할 모든 사람들은 이미 알고 있기 때문에for(;;)
읽을 수 은 의미가 수 있는 수 .이데올로기 때문에
그것은 매우 주관적이다.저는 이렇게 쓰고 있습니다.
while(true) {} //in C++
왜냐하면 그 의도는 매우 명확하고 읽을 수도 있기 때문입니다.그것을 보면 무한 루프가 의도되어 있다는 것을 알 수 있습니다.
라고 도 있다for(;;)
또한 명확합니다.그러나 이 옵션은 복잡한 구문 때문에 무한 루프라는 결론에 도달하기 위해서는 추가 지식이 필요하기 때문에 비교적 명확하지 않다고 생각합니다.심지어 더 많은 수의 프로그래머들이 이 모든 것을 알지 못하는for(;;)
알고 )for
loop) 단, 거의 모든 프로그래머가 알고 있습니다.while
정보를 수 있는지 알 수 있습니다.while(true)
나에게, 글쓰기for(;;)
은 '무한루프'를 쓰는 것과 .while()
무한 루프를 의미합니다.전자는 동작하지만 후자는 동작하지 않습니다.전자의 경우, 빈 상태는true
암묵적으로, 하지만 후자의 경우에는 오류입니다!나는 개인적으로 그것을 좋아하지 않았다.
, 이제while(1)
이치노?'라고 .while(1)
?이 안 돼while(2)
,while(3)
★★★★★★★★★★★★★★★★★」while(0.1)
뭐, 뭘 쓰시든간에, 사실 그 말은 while(true)
건 어떨까요? - 하다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다, 쓰다.
C에는 (내가 글을 쓴다면) 다음과 같이 쓸 것이다.
while(1) {} //in C
한편, 「 」는, 「 」, 「 」의 사이에while(2)
,while(3)
★★★★★★★★★★★★★★★★★」while(0.1)
츠키노, 「C」라고 .while(1)
왜냐하면 많은 C 프로그래머들이 이것을 쓰고 있고 나는 표준에서 벗어날 이유를 찾을 수 없기 때문이다.
정말 지루해서 몇 가지 버전의 루프를 써서 맥 미니에 GCC로 컴파일했습니다.
while(1){}
★★★★★★★★★★★★★★★★★」for(;;) {}
는 결과를 수 있었습니다.do{} while(1);
하지만 다른 코드를
잠시/잠시만 이 일을 끝내다.
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl $0, -4(%rbp)
LBB0_1: ## =>This Inner Loop Header: Depth=1
jmp LBB0_1
.cfi_endproc
do while 루프도 있습니다.
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl $0, -4(%rbp)
LBB0_1: ## =>This Inner Loop Header: Depth=1
jmp LBB0_2
LBB0_2: ## in Loop: Header=BB0_1 Depth=1
movb $1, %al
testb $1, %al
jne LBB0_1
jmp LBB0_3
LBB0_3:
movl $0, %eax
popq %rbp
ret
.cfi_endproc
용 i i i i를 쓴다.for(;/*ever*/;)
.
읽기 쉽고, 타이핑에 시간이 걸리기 때문에(별표가 바뀌기 때문에), 이러한 루프 타입을 사용할 때는 매우 주의해야 합니다.조건부로 표시되는 녹색 텍스트도 매우 이상한 표시입니다.이것은, 이 구조가 반드시 필요한 경우를 제외하고, 눈살을 찌푸리게 하는 또 다른 표시입니다.
가 좋아하는 것 while (true)
:
https://stackoverflow.com/a/224142/1508519
https://stackoverflow.com/a/1401169/1508519
https://stackoverflow.com/a/1401165/1508519
https://stackoverflow.com/a/1401164/1508519
https://stackoverflow.com/a/1401176/1508519
SLaks에 따르면 컴파일은 동일합니다.
Ben Zotto도 상관 없다고 말합니다.
더 빠르지 않아요.정말로 관심이 있는 경우는, 사용의 플랫폼의 어셈블러 출력을 사용해 컴파일 해, 확인해 주세요.그건 중요하지 않아.이건 중요하지 않아.무한 루프를 원하는 대로 쓰세요.
사용자 1216838에 대한 응답으로 결과를 재현해 보겠습니다.
여기 제 기계가 있습니다.
cat /etc/*-release
CentOS release 6.4 (Final)
gcc 버전:
Target: x86_64-unknown-linux-gnu
Thread model: posix
gcc version 4.8.2 (GCC)
테스트 파일:
// testing.cpp
#include <iostream>
int main() {
do { break; } while(1);
}
// testing2.cpp
#include <iostream>
int main() {
while(1) { break; }
}
// testing3.cpp
#include <iostream>
int main() {
while(true) { break; }
}
명령어는 다음과 같습니다.
gcc -S -o test1.asm testing.cpp
gcc -S -o test2.asm testing2.cpp
gcc -S -o test3.asm testing3.cpp
cmp test1.asm test2.asm
유일한 차이점은 첫 번째 줄(파일명이라고도 함)입니다.
test1.asm test2.asm differ: byte 16, line 1
출력:
.file "testing2.cpp"
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.text
.globl main
.type main, @function
main:
.LFB969:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
nop
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE969:
.size main, .-main
.type _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB970:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
cmpl $1, -4(%rbp)
jne .L3
cmpl $65535, -8(%rbp)
jne .L3
movl $_ZStL8__ioinit, %edi
call _ZNSt8ios_base4InitC1Ev
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
call __cxa_atexit
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE970:
.size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB971:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $65535, %esi
movl $1, %edi
call _Z41__static_initialization_and_destruction_0ii
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE971:
.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
.section .ctors,"aw",@progbits
.align 8
.quad _GLOBAL__sub_I_main
.hidden __dso_handle
.ident "GCC: (GNU) 4.8.2"
.section .note.GNU-stack,"",@progbits
★★★★★★★★★★★★★★★★ -O3
물론 출력은 상당히 적지만 여전히 차이가 없습니다.
싶다while (1) { }
★★★★★★★★★★★★★★★★★」while (true) { }
이것은 대부분의 프로그래머들이 쓰는 글입니다.읽기 쉬운 이유로 당신은 일반적인 관용구를 따라야 합니다.
(그렇다면 대부분의 프로그래머에 대한 주장에 대해 분명한 "인용 필요"가 있습니다.하지만 1984년 이후 C에서 본 코드로 볼 때 사실인 것 같습니다.
합리적인 컴파일러라면 모두 같은 코드로 컴파일 할 수 있습니다.단, 임베디드 시스템이나 다른 특수한 시스템에 대해 불합리한 컴파일러가 있다고 해도 놀라지 않습니다.
C 로은 C++이다.for(;;)
폼 테스트 폼의 누락.do/while
★★★★★★★★★★★★★★★★★」while
루프에는 이 특별한 기능이 없습니다.테스트 표현은 필수입니다.
for(;;)
'루프 while true'는 '루프 while true'입니다.사실끝없이 표현하고 .끝없이 루프'를 표현하고 있습니다.불필요한 조건은 없습니다.
때문에 '이러한'은for(;;)
construct는 표준 엔드리스 루프입니다.이건 사실이다.
남은 것은 정례적인 무한 루프를 쓸 것인가, 아니면 불필요한 표현을 만들기 위해 여분의 식별자와 상수를 포함하는 바로크적인 것을 선택할 것인가 하는 것입니다.
의 테스트 표현이while
선택 사항이었지만, 그렇지 않았습니다.while();
이상할 것 같아요. while
네? 반대로, 그 질문에 대한 답은for
뭐? 왜, 영원히!농담삼아 과거 프로그래머 중에는 빈 매크로를 정의하고 있는 사람도 있기 때문에for(ev;e;r);
.
while(true)
보다 우수하다while(1)
적어도 1이 진실을 나타내는 크러지는 포함되지 않았으니까요하지만,while(true)
C99가 될 때까지 C에 들어가지 않았습니다. for(;;)
1978년 책 K&R1에 기술된 언어로 거슬러 올라가는 C의 모든 버전에 존재하며, C++의 모든 방언, 심지어 관련된 언어에도 존재한다.C90으로 작성된 코드 베이스로 코드화할 경우 자신의 코드를 정의해야 합니다.true
위해서while (true)
.
while(true)
잘 안 읽힌다.무엇이 진실일까?우리는 정말로 식별자를 보고 싶지 않다.true
부울 변수를 초기화하거나 할당하는 경우를 제외하고 코드로 지정합니다. true
조건부 테스트에 나타나지 않아도 됩니다.좋은 코딩 스타일은 다음과 같은 번거로움을 방지합니다.
if (condition == true) ...
다음을 지지합니다.
if (condition) ...
이 때문에while (0 == 0)
보다 우수하다while (true)
: "loop while zero is 0"이라는 문장으로 바뀌는 무언가를 테스트하는 실제 조건을 사용합니다."while"과 잘 어울리려면 술어가 필요합니다. "true"라는 단어는 술어가 아니라 관계 연산자입니다.==
이에요.
둘 다 똑같아요.그러나 나는 가장 잘 표현되는 "while(ture)"을 제안한다.
그들은 아마 거의 같은 기계어로 컴파일 될 것이기 때문에 취향에 따라 달라집니다.
개인적으로는 가장 명확한 것을 선택합니다(즉, 무한 루프라고 하는 것이 매우 명확합니다).
나는 에 기댈 것이다.while(true){}
.
어떤 양식을 선택해야 합니까?
어느쪽이든 선택하실 수 있습니다.선택의 문제입니다.모두 동등합니다. while(1) {}/while(true){}
프로그래머가 무한 루프에 자주 사용합니다.
음, 이건 맛이 참 많네요.나는 C배경 출신이 "영원히"라고 읽히는 (;;)를 더 선호한다고 생각한다.일을 위해서라면 지역 주민들이 하는 일을 하고, 자신을 위해서라면 가장 쉽게 읽을 수 있는 것을 하세요.
하지만 제 경험상, (1);는 거의 사용하지 않는 동안 { }을(를) 수행했습니다.
모두 같은 기능을 수행하며, 원하는 것을 선택하는 것은 사실입니다."while(1) or while(true)"을 사용하는 것이 좋은 방법이라고 생각할 수 있습니다.
언급URL : https://stackoverflow.com/questions/20186809/endless-loop-in-c-c
'programing' 카테고리의 다른 글
자바에서는 언제 Atomic Boolean을 사용해야 하나요? (0) | 2022.08.31 |
---|---|
Vuetify 구성 요소에서 계산된 속성 및 Vuex와 함께 Vue v-model 바인딩을 사용하는 방법은 무엇입니까? (0) | 2022.08.30 |
Vue.js 2 어플리케이션에서 onbeforeunload를 모방하려면 어떻게 해야 합니까? (0) | 2022.08.30 |
Vue: 사용자 지정 구성 요소에서 파생된 사용자 지정 구성 요소에서 v-model 및 입력 이벤트 (0) | 2022.08.30 |
C의 파일 끝에 추가 (0) | 2022.08.30 |