왜 postfix 증가가 있습니까?


55

면책 조항 : 접두사와 접미사 증가의 의미를 완벽하게 알고 있습니다. 그들이 어떻게 작동하는지 설명하지 마십시오.

스택 오버플로에 대한 질문을 읽으면 프로그래머가 접미사 증가 연산자에 의해 반복해서 혼란스러워한다는 것을 알 수는 없습니다. 이것으로부터 다음과 같은 질문이 발생합니다. postfix 증가가 코드 품질 측면에서 실질적인 이점을 제공하는 사용 사례가 있습니까?

예를 들어 내 질문을 명확히 해 드리겠습니다. 다음은 매우 간결한 구현입니다 strcpy.

while (*dst++ = *src++);

그러나 그것은 내 책에서 가장 자체적으로 문서화 된 코드는 아닙니다 (그리고 제정신 컴파일러에 대해 두 가지 성가신 경고를 생성합니다). 그렇다면 다음 대안의 문제점은 무엇입니까?

while (*dst = *src)
{
    ++src;
    ++dst;
}

그런 다음 조건에서 혼란스러운 할당을 제거하고 완전히 경고없는 코드를 얻을 수 있습니다.

while (*src != '\0')
{
    *dst = *src;
    ++src;
    ++dst;
}
*dst = '\0';

(그래, 난 알고, src그리고 dst이러한 대안 솔루션의 다른 결말 값을해야하지만 이후 strcpy즉시 루프 후 반환,이 경우에는 문제가되지 않습니다.)

postfix 증가의 목적은 가능한 한 코드를 간결하게 만드는 것입니다. 나는 이것이 어떻게 우리가 노력해야 하는지를 보지 못합니다. 이것이 원래 성능에 관한 것이라면 오늘날에도 여전히 관련이 있습니까?


7
접미사 변형이 가장 일반적으로 사용되는 변형이므로 이에 대해 사례를 작성하려는 경우 꽤 강력한 사례가 좋습니다. 그리고 첫 번째 예는 약간의 짚맨입니다. 왜냐하면 소수의 사람들이 실제로이 strcpy방법으로 코드를 작성한다고 생각 하기 때문입니다 (이미 언급 한 이유로).
Robert Harvey

4
왜 하나가 있습니까?
James McNellis

31
프로그래머를 혼동시킬 가능성이있는 언어에서 모든 것을 제거하면 기능이 많지 않을 것입니다. 무언가가 당신에게 유용하지 않거나 매우 드물게 사실이라는 것은 그것이 도둑질되어야한다는 것을 의미하지는 않습니다. 더 이상 관련이 없으면 사용하지 마십시오. 끝.
코디 그레이

4
네,하지만 당신은 절대 할 수 없습니다int c = 0; c++;
Biff MaGriff

4
@Cody : 혼란스럽고 유용한 것이 있기 때문입니다. 그는 증분 후 자체로 혼동하지 않고 유용성 에 대해 혼동합니다 . 쓸모없고 혼란 스럽거나 혼동되지 않는 것은 없어야합니다.
GManNickG

답변:


23

한 번 성능에 영향을 미쳤지 만 실제 이유는 의도를 깨끗하게 표현하기위한 것이라고 생각합니다. 실제 질문은 무언가 while (*d++=*s++);가 의도를 명확하게 표현 하는지 여부 입니다. IMO는 그 대안을 제시 하지만 대안이 명확하다는 것을 알았습니다. 하지만 이는 수십 년 동안 일이 수행되는 방식에 익숙해 져서 발생했을 수 있습니다. K & R에서 C를 배웠다면 (C에는 거의 다른 책 없었기 때문에 ) 아마 도움이 될 것입니다.

어느 정도까지는 오래된 코드에서 간결함이 훨씬 더 중요하다는 것이 사실입니다. 개인적으로, 나는 이것이 아주 좋은 것이라고 생각합니다. 몇 줄의 코드를 이해하는 것은 보통 사소한 일입니다. 어려운 것은 많은 양의 코드를 이해하는 것입니다. 테스트와 연구에 따르면 화면의 모든 코드를 한 번에 맞추는 것이 코드를 이해하는 데 중요한 요소라는 점이 반복적으로 나타났습니다. 화면이 확장됨에 따라 이것은 사실로 유지되므로 코드를 (합리적으로) 간결하게 유지하는 것이 중요합니다.

물론 선상으로 갈 수는 있지만 이것이 아니라고 생각합니다. 특히, 한 줄의 코드를 이해하는 것이 극도로 어려워 지거나 시간이 많이 걸리는 경우, 특히 더 적은 수의 코드 줄을 이해하면 더 많은 줄을 이해하는 것보다 더 많은 노력을 기울일 때이 문제가 극복 될 것이라고 생각합니다. Lisp와 APL에서는 빈번하지만, (적어도 나에게는) 그렇지 않습니다.

컴파일러 경고에 대해 덜 걱정합니다. 많은 컴파일러가 상당히 정기적으로 엄청나게 경고를내는 경험입니다. 분명히 사람들이 자신의 코드 (및 경고가 발생할 수있는 경고)를 이해해야 한다고 생각하지만 일부 컴파일러에서 경고를 유발하는 괜찮은 코드가 반드시 잘못된 것은 아닙니다. 물론 초보자는 항상 안전하게 무시할 수있는 것을 알지 못하지만 초보자는 영원히 머무를 필요가 없으며 우리처럼 코딩 할 필요도 없습니다.


12
간결한 버전이 우리 중 일부에게 읽기 쉽다 는 것을 지적한 +1 . :-)

1
당신이 당신의 컴파일러 경고의 일부를 좋아하지 않는 경우에 (내가없이 할 수있는 몇 가지 더있다 - 심각, 내가 의미 유형 if(x = y), 나는 맹세한다!) 당신이 실수를 놓치지 않도록 당신이 당신의 컴파일러의 경고 옵션을 조정해야 당신 좋아하는 경고 .

4
@Brooks 모세 : 나는 해요 많은 덜 힘이 그것에 대해. 컴파일러의 단점을 보완하기 위해 코드를 오염시키는 것을 좋아하지 않습니다.
Jerry Coffin

1
@Jerry, @Chris :이 주석은 일반적으로 경고가 좋은 것으로 생각되는 경우를위한 것이지만, 비정상적인 작업을 수행하는 특정 행에는 적용하지 않으려 고합니다. 경고를 원하지 않고 단점을 고려 -Wno-X한다면을 사용하십시오. 단 , 예외를 하나만 적용하고 다른 곳에서 경고를 적용하려면 Chris가 말하는 것처럼 후프 점핑을 사용하는 것보다 훨씬 이해하기 쉽습니다. .

1
@Brooks : 이중 괄호와 (void)x사용하지 않는 경고를 침묵 시키는 것은 유용한 경고를 침묵시키는 숙어입니다. 주석은 조금처럼 보이지만 pragmas휴대하기가 쉽지 않습니다 : /
Matthieu M.

32

하드웨어 오류였습니다.


당신이 알아 차리게 흥미 롭다. Postfix 증가는 아마도 완벽하게 좋은 이유가 많을 수도 있지만 C의 많은 것들과 마찬가지로 인기도 는 언어의 기원으로 추적 될 수 있습니다.

C는 다양한 초기 및 저전력 시스템에서 개발되었지만 C 및 Unix는 PDP-11의 메모리 관리 모델로 상대적으로 큰 인기를 얻었습니다. 이들은 비교적 중요한 컴퓨터 였고 Unix는 -11에서 사용할 수있는 다른 7 개의 초라한 운영 체제보다 훨씬 뛰어 났습니다 .

PDP-11에서도 마찬가지입니다.

*--p

*p++

... 어드레싱 모드 로 하드웨어에서 구현 되었습니다 . (또한 *p,하지만 다른 조합.) 그 초기 기계에서 모든 미만 0.001 GHz의, 루프에서 명령 또는 두 개의 저장 거의 대기-A-초-A-분을 기다리거나 이동 - 아웃을위한 없었다해야한다 점심 차이. 이것은 구체적으로 포스트 증가에 대해 말하지는 않지만 포인터 포스트 증가가있는 루프는 당시 색인보다 훨씬 좋을 수 있습니다.

결과적으로 C 관용구가 C 멘탈 매크로가 되었기 때문에 디자인 패턴이 나타납니다.

그것은 {C89가 최신이기 때문에 이것이 요구 사항이 아니었지만 지금은 코드 패턴입니다.

업데이트 : 분명히 *p++언어 의 주된 이유 는 언어가 자주하고 싶어하는 것이기 때문입니다. 코드 패턴의 인기 는 PDP-11이 도착하기 전에 약간 디자인 된 언어의 기존 패턴과 일치하는 인기있는 하드웨어에 의해 강화 되었습니다.

요즘에는 어떤 패턴을 사용하거나 인덱싱을 사용하는 경우 아무런 차이가 없으며 일반적으로 상위 수준에서 프로그래밍하지만 0.001GHz 시스템에서 많은 문제가 있었으며 다른 것을 사용 *--x하거나 *x++의미가 없었습니다. PDP-11을 "받지 못했습니다", 사람들이 당신에게 와서 "알고 있었나요?"라고 말했을 것입니다 :-) :-)


25
위키 백과는 말한다 : "A (false)를 민속 신화는 PDP-11의 명령어 세트 아키텍처는 C 프로그래밍 언어의 관용적 사용에 영향을 것을 인 PDP-11의 증가 및 감소 어드레싱 모드가에 해당합니다. −−i그리고 i++C. 만약에 구조 ij두 레지스터 변수 같은 식이었다 *(−−i) = *(j++).. 하나의 머신 명령어로 컴파일 될 수는 [...] 데니스 리치 모호이 포크 신화 모순 [은 C 언어의 개발 ] "
fredoverflow

3
허 (FredOverflow의 의견에서 제공된 링크에서) : "사람들은 종종 C와 Unix가 처음으로 인기를 얻은 DEC PDP-11에서 제공하는 자동 증가 및 자동 감소 주소 모드를 사용하기 위해 만들어진 것으로 추측합니다. B가 개발 될 때 PDP-11이 없었기 때문에 불가능하다. 그러나 PDP-7은 몇 개의 '자동 증가'메모리 셀을 가지고 있으며,이를 통해 간접 메모리 참조는 셀을 증가 시켰다는 특성을 가지고있다. 그런 연산자들을 톰슨에게 제안했다.

3
DMR은 PDP-11이 C에 첨가 된 이유가 아니라고 말했다. 나도 그렇게 말했다. 내가 말한 것은 PDP-11을 활용하는 데 사용되었으며 정확한 이유로 대중적인 디자인 패턴이되었다는 것입니다. Wikipedia 그와 상반되는 경우 단순히 잘못되었지만, 나는 그런 식으로 읽지 않습니다. 해당 W 페이지에 잘못 표현되어 있습니다.
DigitalRoss

3
@FredOverflow. "민화 속의 신화"가 무엇인지 정확히 이해하지 못했다고 생각합니다. 신화는 C가 존재하지 않는 것이 아니라 코드 패턴이 인기를 얻지 못했다는 것이 아니라 11 개의 op를 활용하도록 설계되었다는 것입니다. 확실하지 않은 경우 : PDP-11은 실제로 거의 모든 명령에 대해 주소 지정 모드로 하드웨어에서이 두 가지 모드를 실제로 구현하며 실제로 C가 실행 된 첫 번째 중요한 기계 였습니다 .
DigitalRoss

2
"이 0.001GHz 시스템에서 많은 문제가 발생했을 것입니다." 음, 나는 그것이 데이트하기 때문에 말하기를 싫어하지만 CPU에 대한 Motorola 및 Intel 설명서가 지침의 크기와 소요되는주기를 조회하도록했습니다. 프린트 스풀러에 하나 이상의 기능을 추가 할 수 있고 몇 사이클을 절약 할 수있는 가장 작은 코드를 발견하면 직렬 포트가 새로 발명 된 MIDI와 같은 프로토콜을 유지할 수 있습니다. C는 특히 컴파일러가 개선됨에 따라 일부 nit-picking을 완화했지만 여전히 코드를 작성하는 가장 효율적인 방법을 아는 것이 중요했습니다.
Tin Man

14

접두사와 접미사 --++연산자는 켄 톰슨에 의해 B 언어 (C의 전신)에 도입되었다 - 그리고 아니, 그들은 PDP-11, 당시 존재하지 않았던 영감되지 않았다.

Dennis Ritchie의 "C 언어의 개발" 에서 인용 :

톰슨 발명에 의해 한 단계 더 갔다 ++--증가 또는 감소하는 연산자; 접두사 또는 접미사 위치는 피연산자의 값을 기록하기 전 또는 후에 변경이 발생하는지 여부를 결정합니다. 그들은 초기 버전의 B에는 없었지만 그 길을 따라 나타났습니다. 사람들은 종종 C와 Unix가 처음으로 인기를 얻은 DEC PDP-11에서 제공하는 자동 증가 및 자동 감소 주소 모드를 사용하기 위해 만들어 졌다고 생각합니다. B가 개발되었을 때 PDP-11이 없었기 때문에 역사적으로 불가능합니다. 그러나 PDP-7에는 몇 개의 '자동 증가'메모리 셀이 있었으며,이를 통해 간접 메모리 참조가 셀을 증가시키는 특성이있었습니다. 이 기능은 아마도 그러한 연산자를 Thompson에게 제안했을 것입니다. 접두사와 접미사를 모두 만드는 일반화는 그 자체였습니다. 과연,++x보다 작습니다 x=x+1.


8
아니요, 저는 Ken Thompson과 관련이 없습니다.
Keith Thompson

이 매우 흥미로운 참조 주셔서 감사합니다! 이것은 기술 최적화보다는 압축의 목표를 제안한 원래의 K & R에서 인용 한 것입니다. 그러나 나는이 연산자들이 이미 B에 존재했다는 것을 몰랐습니다.
Christophe

@BenPen 내가 아는 한 , 두 질문이 각각의 사이트에 맞는 한 다른 SE 사이트 에 중복이 있으면 질문을 닫는 정책이 없습니다 .
Ordous

흥미 롭다 ... 프로그래머는 확실히 의문의 여지가 없다.
BenPen

@ BenPen : Stack Overflow 질문에 대한 대답은 이미 내가 한 것과 동일한 소스를 인용합니다 (많지는 않지만).
Keith Thompson

6

사후 증가 연산자가 존재하는 명백한 이유 는 장소 전체 (++x,x-1)또는 (x+=1,x-1)전체에 식을 쓰거나 이해할 수없는 부작용이있는 사소한 문구를 여러 명령문으로 쓸데없이 분리 할 필요가 없기 때문 입니다. 여기 몇 가지 예가 있어요.

while (*s) x+=*s++-'0';

if (x) *s++='.';

문자열을 순방향으로 읽거나 쓸 때마다 사전 증가가 아닌 후행 증가는 거의 항상 자연스러운 작업입니다. 나는 사전 증분에 대한 실제 사용을 거의 경험하지 못했으며, 사전 감소를 위해 찾은 유일한 주요 용도는 숫자를 문자열로 변환하는 것입니다 (인간 쓰기 시스템은 숫자를 거꾸로 쓰기 때문에).

편집 : 실제로 그것은 그렇게 추악하지는 않습니다. 대신 (++x,x-1)당신 물론 사용할 수 있습니다 ++x-1또는 (x+=1)-1. 여전히 x++더 읽기 쉽습니다.


두 시퀀스 포인트 사이에서 변수를 수정하고 읽으므로 해당 표현식에주의해야합니다. 이러한 식의 평가 순서는 보장되지 않습니다.

@ 눈사람 : 어느 것? 내 대답에는 그러한 문제가 없습니다.
R ..

(++x,x-1)(함수 호출, 아마도?) 와 같은 것이 있다면

@ Snowman : 그것은 함수 호출이 아닙니다. 우선 순위를 제어하기 위해 괄호로 묶은 시퀀스 포인트 인 C 쉼표 연산자입니다. 결과는 x++대부분의 경우 와 동일합니다 (한 가지 예외 : x순위가 낮은 부호없는 유형 int이고 초기 x값은 해당 유형의 최대 값임).
R ..

아, 까다로운 쉼표 연산자 ... 쉼표가 쉼표가 아닌 경우. 쉼표 연산자의 괄호와 희귀 성은 나를 버렸습니다. 신경 쓰지 마!

4

PDP-11은 명령 세트에서 증가 후 및 감소 후 작업을 제공했습니다. 이제 이것들은 지침이 아니 었습니다. 그것들은 레지스터가 증가하기 전이나 감소 된 후에 레지스터의 값을 원한다는 것을 지정할 수있게 해주는 명령 수정 자입니다.

기계 언어의 단어 복사 단계는 다음과 같습니다.

movw (r1)++,(r2)++

레지스터를 통해 한 위치에서 다른 위치로 단어를 이동 시켰으며 레지스터는 다시 할 준비가되었습니다.

C가 PDP-11을 기반으로 구축되면서 C에 도입 된 유용한 개념이 많이 발견되었습니다. C는 어셈블러 언어를 대체 할 수있는 유용한 도구였습니다. 사전 증가 및 사후 감소가 대칭을 위해 추가되었습니다.


그것은 훌륭한 수정 자입니다 ... PDP-11 어셈블리를 배우고 싶습니다. BTW, "대칭"에 대한 참조가 있습니까? 말이 되겠지만 이것은 역사입니다. 때로는 말이되지 않았습니다. LOL
BenPen

2
주소 지정 모드 라고도 합니다 . PDP-11은 증분 후 및 사전 감소를 제공하여 스택 작업을 위해 훌륭하게 결합되었습니다.
Erik Eidt

1
PDP-8은 증분 후 메모리 간접을 제공했지만 해당하는 사전 감소 작업은 없습니다. 마그네틱 코어 메모리를 사용하면 메모리 단어를 읽으면 그것을 지우고 (!), 프로세서는 다시 쓰기 기능을 사용하여 읽은 단어를 복원합니다. 다시 쓰기 전에 증분을 적용하는 것이 자연스럽게 이루어졌으며보다 효율적인 블록 이동이 가능해졌습니다.
Erik Eidt

3
죄송합니다. PDP-11은 이러한 운영자에게 영감을주지 않았습니다. Ken Thompson이 발명했을 때 아직 존재하지 않았습니다. 내 답변을 참조하십시오 .
Keith Thompson

3

나는 그것이 정말로 필요했던 것을 의심한다. 내가 아는 한, 루프에서 사전 증분을 사용하는 것보다 대부분의 플랫폼에서 더 컴팩트 한 것으로 컴파일되지 않습니다. 그것이 만들어 질 당시에는 코드의 간결함이 코드의 선명도보다 더 중요했습니다.

즉, 코드의 선명도가 중요하지는 않지만 (또는 중요하지 않은) 것은 아니지만 모든 키 입력으로 인해 낮은 보드 모뎀 (보드에서 측정하는 것은 느림)에 입력 할 때 패리티 검사로 사용되는 단일 비트를 사용하여 메인 프레임을 한 번에 한 바이트 씩 다시 반향 할 수 있으므로 많이 입력하지 않아도됩니다.

이것은 &와 | ==보다 우선 순위가 낮은 연산자

최고의 의도 (& & 및 ||의 비 단락 버전)로 설계되었지만 이제는 프로그래머를 혼란스럽게하며 결코 바뀌지 않을 것입니다.

어쨌든, 이것은 귀하의 질문에 대한 좋은 대답이 없다고 생각한다는 대답에 불과하지만, 나보다 더 전문가 코더에 의해 아마도 틀릴 것입니다.

--편집하다--

나는 둘 다 믿을 수 없을만큼 유용하다는 것을 알았 습니다. 다른 사람이 좋아하든 그렇지 않든 바뀌지 않을 것이라고 지적하고 있습니다.


이것은 원격으로는 사실이 아닙니다. "코드의 간결함 " 이 명확성보다 더 중요한 것은 없었 습니다.
코디 그레이

글쎄, 나는 그것이 훨씬 더 중점적이라고 주장했다. 그러나 당신은 꽤 옳습니다 . 코드 명료성보다 훨씬 중요 하지는 않습니다 ... 대부분의 사람들에게.

6
음, "간결한"의 정의는 코드를 작성할 때 일반적으로 좋은 일입니다 둘 다 "여분의 결여, 몇 가지 단어를 사용하여"또는 "연마 원활 우아한"입니다. "Terse"는 많은 사람들이 생각하는 것처럼 "모호하고 읽기 어렵고 난독하다"는 의미는 아닙니다.
James McNellis

@ 제임스 : 당신이 옳기는하지만, 대부분의 사람들은 프로그래밍 문맥에서 그것을 사용할 때 "단어"의 두 번째 정의를 의미 한다고 생각 합니다. 이 정의에 따르면 특정 코드의 간결성과 표현력 사이에 상충 관계가있는 상황을 상상하기가 훨씬 쉽습니다. 분명히 코드를 작성할 때해야 할 올바른 일은 말할 때와 똑같습니다. 필요한만큼 짧게 만들지 만 더 짧게 만들지 마십시오. 표현력에 대한 간결함을 소중히 간과하면 코드가 난독 해 보일 있지만 반드시 그렇지는 않습니다.
코디 그레이

1
40 년 되 감고 약 1000 자 만 저장할 수있는 드럼에 프로그램을 맞추거나 컴파일러를 작성하면 4 천 바이트의 램으로 만 작동한다고 상상해보십시오. 간결함과 명료 함이 문제가되지 않는 경우가있었습니다. 간결해야했습니다.이 행성에는 간결하지 않은 프로그램을 저장, 실행 또는 컴파일 할 수있는 컴퓨터가 없었습니다.
nos

3

포인터를 처리 할 때 (역 참조 여부에 관계없이) 접미사 애퍼 레이터를 좋아합니다.

p++

보다 자연스럽게 "다음 지점으로 이동"으로 읽습니다.

p += 1

sizeof (* p)! = 1 인 포인터로 처음 사용했을 때 초보자를 혼동해야합니다.

혼란 문제를 올바르게 진술하고 있습니까? 초보자를 혼란스럽게하는 것은 접미사 ++ 연산자가 역 참조 * 연산자보다 우선 순위가 높다는 사실이 아닙니다.

*p++

로 파싱

*(p++)

그리고 아닙니다

(*p)++

일부는 예상 할 수 있습니까?

(그게 나쁘다고 생각하십니까? C 선언 읽기를 참조하십시오 .)


2

좋은 프로그래밍의 미묘한 요소 중에는 지역화미니멀리즘이 있습니다 .

  • 최소한의 사용 범위에서 변수 배치
  • 쓰기 액세스가 필요하지 않은 경우 const 사용
  • 기타

같은 정신에서 x++의 현재 값에 대한 참조 현지화하는 방법으로 볼 수있다 x적어도 지금은 - - 동안 즉시했습니다 나타내는 여부를 그 값으로 완성하고 (다음으로 이동 유효 할 xint또는 포인터 또는 반복자). 약간의 상상력만으로도 x더 이상 필요하지 않은 즉시 이전 값 / 위치가 "범위를 벗어난"상태가되고 새로운 값으로 이동하는 것과 비교할 수 있습니다. 전환이 가능한 정확한 지점은 접미사로 강조 표시됩니다++ . 이것이 아마도 "이전"의 최종 사용이라는 의미 x는 프로그래머가 주변 코드를 스캔 할 때 도움이되는 알고리즘에 대한 귀중한 통찰력이 될 수 있습니다. 물론, 접미사++ 프로그래머가 새로운 가치의 사용에 대한 경계를 세울 수 있습니다. 이것은 새로운 가치가 실제로 필요한시기에 따라 좋을 수도 있고 그렇지 않을 수도 있습니다. 상황에 도움이됩니다.

많은 초보자가 기능으로 인해 혼란 스러울 수 있지만, 장기적인 이점과 균형을 맞출 가치가 있습니다. 초보자는 초보자가 오랫동안 머 무르지 않습니다.


2

와우, 많은 답변이 무의미한 것입니다 (대담한 경우). 명백한 점을 지적하지 않는 명백한 점을 지적한다면 특히 용서하십시오. (Stroustrup의 관점에서 볼 때) 아직 게시되지 않은 것 같습니다! :)

Postfix x++는 표현식에서 '위쪽'으로 전달되는 임시 변수를 생성하지만 변수 x는 이후에 증가합니다.

접두사 ++x는 임시 객체를 생성하지 않지만 'x'를 증가시키고 결과를 표현식에 전달합니다.

운영자를 아는 사람들에게는 그 가치가 편리합니다.

예를 들면 다음과 같습니다.

int x = 1;
foo(x++); // == foo(1)
// x == 2: true

x = 1;
foo(++x); // == foo(2)
// x == 2: true

물론,이 예제의 결과는 다른 동등한 (그리고 아마도 덜 경 사진) 코드에서 생성 될 수 있습니다.

그렇다면 왜 postfix 연산자가 있습니까? 나는 그것이 혼란스러워 졌음에도 불구하고 지속되는 관용구이기 때문에 추측합니다. 한때 가치가 있다고 여겨지는 레거시 구조이지만,인지 된 가치가 편의성과 같이 성능면에서 그렇게 많이 확신하지는 않습니다. 그 편리함은 잃어 버리지 않았지만 가독성에 대한 인식이 높아져서 운영자의 목적에 의문을 제기했다고 생각합니다.

더 이상 접미사 연산자가 필요합니까? 아마 아닐 것입니다. 그 결과 혼란스럽고 이해력에 장애가됩니다. 일부 훌륭한 코더들은 특히 "PERL-esque"의 아름다움을 가진 곳에서 유용한 곳을 즉시 알 수 있습니다. 그 아름다움의 비용은 가독성입니다.

명시 적 코드가 간결성, 가독성, 이해성 및 유지 관리성에 비해 이점이 있음에 동의합니다. 훌륭한 디자이너와 관리자는 그것을 원합니다.

그러나 일부 프로그래머는 postfix 연산자와 같이 아름답고 단순하게 만들 수있는 코드를 생성하도록 장려하는 특정 아름다움이 있습니다. 그것은 피투성이 임에도 불구하고 더 바람직하지는 않지만 더 아름답게 만드는 어떤 것이 있습니다.

다시 말해서, 어떤 사람들 while (*dst++ = *src++);은 캔버스보다 솔처럼 마치 단순하게 숨을 쉴 수있는 더 아름다운 해결책이라는 것을 알게됩니다. 아름다움을 높이기 위해 언어를 이해해야한다는 것은 그 아름다움에 그치지 않습니다.


3
+1 "일부 사람들은 (* dst ++ = * src ++); 더 아름다운 해결책을 찾기 위해 노력합니다." 명확히. 어셈블리 언어를 이해하지 못하는 사람들은 실제로 C가 얼마나 우아 할 수 있는지 이해하지 못하지만 특정 코드 문장은 빛나는 별입니다.
Tin Man

"우리는 더 이상 접미사 연산자가 필요합니까? 그렇지 않습니다." -튜링 머신을 생각하는 데 도움이 될 수 없습니다. 우리는 지금까지 자동 변수, 필요한 적이 for문, 지옥, 심지어 while(우리가 goto결국를)?

@Bernd : 하! 폐쇄를 상상해보십시오! 폐쇄! 스캔들! lol
Brian M. Hunt

폐쇄! 말도 안돼 테이프 만주세요! 진심으로, 내가 의미하는 것은 / needing /이 기능을 주요 결정 기준으로 생각하지 않는다는 것입니다 (당신이 lisp를 디자인하고 말하고 싶지 않다면). IME 접두사 연산자를 거의 독점적으로 사용하고 (nay, need ) 접두사를 거의 필요로하지 않습니다.

2

Kernighan & Ritchie의 정당성 검증 (Original K & R page 42 and 43)을 보자 :

특이한 측면은 ++와-를 접두사 또는 접미사로 사용할 수 있다는 것입니다. (...) 원하는 값이없는 상황에서 (..) 취향에 따라 접두사 또는 접두사를 선택하십시오. 그러나 하나 또는 다른 하나가 특별히 요구되는 상황입니다.

텍스트는 " 보다 간결한 "코드 를 작성하려는 명백한 목표를 가지고 인덱스 내에서 증분을 사용하는 몇 가지 예를 계속 합니다. 따라서 이러한 연산자의 이유는보다 컴팩트 한 코드의 편의성입니다.

주어진 ( squeeze(), getline()strcat()) 세 가지 예는 인덱싱을 사용하는 표현식 내에서 접미사 만 사용합니다. 저자는 포함 된 증분을 사용하지 않는 더 긴 버전과 코드를 비교합니다. 이것은 초점이 컴팩트함에 있음을 확인합니다.

102 페이지의 K & R 하이라이트에서는 포인터 역 참조와 함께이 연산자를 사용합니다 (예 : *--p*p--). 더 이상의 예는 제시되지 않았지만 다시 말하지만 이점은 컴팩트 함이 분명합니다.

접두사는 예를 들어 색인 또는 끝에서 쳐다 보는 포인터를 감소시킬 때 매우 일반적으로 사용됩니다.

 int i=0; 
 while (i<10) 
     doit (i++);  // calls function for 0 to 9  
                  // i is 10 at this stage
 while (--i >=0) 
     doit (i);    // calls function from 9 to 0 

1

나는 전제에 동의하지 않을거야 ++p, p++어떻게 든 읽기 어렵거나 불분명하다. 하나는 "p를 증가시키고 p를 읽는다"를 의미하고, 다른 하나는 "p를 읽고 p를 증가시키는 것"을 의미한다. 두 경우 모두 코드의 연산자는 코드 설명의 정확한 위치에 있으므로 ++의미를 알면 결과 코드의 의미를 알 수 있습니다.

당신은 알아 차리기 힘든 코드를 생성 할 수 있는 구문을하지만, 나는 여기에 케이스를 볼 수 없습니다 p++/ ++p입니다 본질적 를 붙일.


1

이것은 전기 기술자의 POV에서 온 것입니다.

후입 선출 (LIFO) 스택을 유지하기 위해 사후 증분 및 사전 감소 연산자가 내장 된 프로세서가 많이 있습니다.

다음과 같습니다.

 float stack[4096];
 int stack_pointer = 0;

 ... 

 #define push_stack(arg) stack[stack_pointer++] = arg;
 #define pop_stack(arg) arg = stack[--stack_pointer];

 ...

나는 몰라,하지만 그것이 접두사와 접두사 증가 연산자를 모두 볼 것으로 예상되는 이유입니다.


1

컴팩트성에 대한 Christophe의 요점을 강조하기 위해 V6의 코드를 모두 보여주고 싶습니다. 이것은 http://minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/source/c/c00.c 의 원본 C 컴파일러의 일부입니다 .

/*
 * Look up the identifier in symbuf in the symbol table.
 * If it hashes to the same spot as a keyword, try the keyword table
 * first.  An initial "." is ignored in the hash.
 * Return is a ptr to the symbol table entry.
 */
lookup()
{
    int ihash;
    register struct hshtab *rp;
    register char *sp, *np;

    ihash = 0;
    sp = symbuf;
    if (*sp=='.')
        sp++;
    while (sp<symbuf+ncps)
        ihash =+ *sp++;
    rp = &hshtab[ihash%hshsiz];
    if (rp->hflag&FKEYW)
        if (findkw())
            return(KEYW);
    while (*(np = rp->name)) {
        for (sp=symbuf; sp<symbuf+ncps;)
            if (*np++ != *sp++)
                goto no;
        csym = rp;
        return(NAME);
    no:
        if (++rp >= &hshtab[hshsiz])
            rp = hshtab;
    }
    if(++hshused >= hshsiz) {
        error("Symbol table overflow");
        exit(1);
    }
    rp->hclass = 0;
    rp->htype = 0;
    rp->hoffset = 0;
    rp->dimp = 0;
    rp->hflag =| xdflg;
    sp = symbuf;
    for (np=rp->name; sp<symbuf+ncps;)
        *np++ = *sp++;
    csym = rp;
    return(NAME);
}

이것은 좋은 스타일의 교육으로 samizdat에 전달 된 코드이지만 오늘날 우리는 결코 그렇게 쓰지 않을 것입니다. 부작용 ifwhile조건 이 얼마나 많이 포함되어 있는지 , 반대로 for루프 본문에서 수행되므로 두 루프에 증분식이없는 방법을 살펴보십시오 . 꼭 필요한 경우 블록을 중괄호로만 묶는 방법을 살펴보십시오.

이것의 일부 는 오늘날 컴파일러가 우리를 위해 할 것으로 예상되는 종류의 수동 미세 최적화였습니다. 그러나 컴퓨터에 대한 전체 인터페이스가 단일 80x25 유리 tty 일 때 코드 를 원한다는 가설을 제시합니다. 최대한 밀도가 높아져 더 많은 내용을 볼 수 있습니다.

(모든 것에 글로벌 버퍼를 사용하는 것은 아마도 어셈블리 언어로 치아를 자르는 것에서 숙취 일 것입니다.)


주의해서 다루십시오 : "ihash = + * sp ++;" 어떤 시점에서 C는 + =뿐만 아니라 = + 연산자를 가졌습니다. 현재 = +는 대입 연산자이고 그 뒤에는 아무것도하지 않는 단항 더하기가 있으므로 "ihash = * sp; sp + = 1;"과 같습니다.
gnasher729

@ gnasher729 예, 나중에 rp->hflag =| xdflg현대 컴파일러에서 구문 오류가 될 것이라고 생각합니다. "어떤 시점에서"는 정확히 V6입니다. +=형태 전환 은 V7에서 일어났습니다. ( 이 코드를 올바르게 읽으면 V6 컴파일러 허용 =+됩니다. 같은 파일에서 symbol () 참조)
zwol

-1

아마도 화장품에 대해서도 생각해야합니다.

while( i++ )

논란의 여지없이 "더 좋아 보인다"

while( i+=1 )

어떤 이유로 증분 후 운영자는 매우 매력적으로 보입니다. 짧고 달콤하며 모든 것을 1 씩 증가시킵니다. 접두사와 비교하십시오.

while( ++i )

"거꾸로 본다"그렇지 않습니까? 누군가 긍정적 인 것 ( +0또는 이와 유사한 것) 을 지정하는 것이 어리석은 경우를 제외하고는 수학에서 더하기 부호 FIRST가 표시되지 않습니다 . 우리는 OBJECT + SOMETHING을 보는 데 익숙합니다.

채점과 관련이 있습니까? A, A +, A ++? 나는 처음에 파이썬 사람들 operator++이 그들의 언어에서 제거되었다는 사실에 대해 매우 치즈를 입었다 고 말할 수 있습니다!


1
귀하의 예는 똑같은 일을하지 않습니다. i++의 원래 값을 반환 i하고, i+=1++i의 원래 값 반환 i하면, 제어 흐름이 문제를 반환 값을 사용하고 이후에 1을 더한를.
David Thornley

네 말이 맞아. 그러나 나는 여기서 가독성만을보고 있습니다.
bobobobo

-2

9에서 0까지 거꾸로 계산 :

for (unsigned int i=10; i-- > 0;)  {
    cout << i << " ";
}

또는 동등한 while 루프.


1
어때요 for (unsigned i = 9; i <= 9; --i)?
fredoverflow
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.