단락 논리 연산자가 필수입니까? 그리고 평가 순서?


140

는 ANSI 표준합니까 임무는 논리 연산자 중 하나를 C 또는 C ++에서 단락이 될?

나는 당신의 코드가 단락 된 작업에 의존해서는 안된다는 K & R 책을 회상합니다. 누군가 표준에서 로직 연산이 항상 단락 된 곳을 지적 할 수 있습니까? 나는 주로 C ++에 관심이 있으며 C에 대한 대답도 훌륭합니다.

또한 평가 순서가 엄격하게 정의되어 있지 않다는 것을 읽은 것을 기억합니다 (어딘지 기억하지 못합니다). 따라서 코드 내에서 표현식 내의 함수가 특정 순서로 실행될 것이라고 가정하거나 의존해서는 안됩니다. 호출되었지만 컴파일러는 가장 효율적인 순서를 자유롭게 선택할 수 있습니다.

표준은이 표현식의 평가 순서를 나타 냅니까?

if( functionA() && functionB() && functionC() ) cout<<"Hello world";

12
주의 : POD 유형에 해당됩니다. 그러나 연산자 && 또는 연산자 || 특정 클래스의 경우 바로 가기를 반복하지 않습니다. 그렇기 때문에 자신의 클래스에 대해 이러한 연산자를 정의하지 않는 것이 좋습니다.
Martin York

기본 부울 대수 연산을 수행하는 클래스를 만들 때 얼마 전에이 연산자를 재정의했습니다. 아마도 "단락과 왼쪽 오른쪽 평가를 파괴합니다!" 내가 잊어 버린 경우에 대비해서 또한 * / +가 오버로드되어 동의어가되었습니다 :-)
Joe Pineda

if-block에 함수 호출을하는 것은 좋은 프로그래밍 관행이 아닙니다. 항상 메소드의 리턴 값을 보유하는 변수를 선언하여 if-block에 사용하십시오.
SR Chaitanya

6
@SRChaitanya 맞지 않습니다. 나쁜 연습으로 임의로 설명하는 것은 항상 여기에서와 같이 부울을 반환하는 함수를 사용하여 수행됩니다.
Lorne의 후작

답변:


154

예, 작업자 ||&&C 및 C ++ 표준 모두에서 단락 및 평가 순서가 필요합니다 .

C ++ 표준은 말합니다 (C 표준에는 동등한 조항이 있어야합니다).

1.9.18

다음 식의 평가에서

a && b
a || b
a ? b : c
a , b

이 표현식에서 연산자의 내장 의미를 사용하면 첫 번째 표현식을 평가 한 후 시퀀스 포인트가 있습니다 (12).

C ++에서 별도의 트랩이있다 : 단락은 않습니다 NOT 유형이 과부하 사업자에 적용 ||하고 &&.

각주 12 :이 단락에 표시된 연산자는 5 절에 설명 된 내장 연산자입니다. 이러한 연산자 중 하나가 유효한 컨텍스트에서 오버로드되어 (13 항) 사용자 정의 연산자 함수를 지정하면 표현식이 지정됩니다. 함수 호출 및 피연산자 는 그들 사이에 내재 된 순서 지점없이 인수 목록을 형성 합니다.

매우 구체적인 요구 사항이 없으면 일반적으로 C ++에서 이러한 연산자를 오버로드하지 않는 것이 좋습니다. 그렇게 할 수는 있지만 다른 사람의 코드에서 예상되는 동작을 깰 수 있습니다. 특히 이러한 연산자가 이러한 연산자를 오버로드하는 유형으로 템플릿을 인스턴스화하여 간접적으로 사용하는 경우에 특히 그렇습니다.


3
단락이 오버로드 된 논리 연산에 적용되지 않는다는 것을 몰랐습니다. 표준 또는 소스에 대한 참조를 추가 할 수 있습니까? 나는 당신을 불신하지 않고 단지 이것에 대해 더 배우고 싶습니다.
Joe Pineda

4
네, 논리적입니다. operator && (a, b)의 인수 역할을합니다. 무슨 일이 일어나는지를 구현하는 것입니다.
Johannes Schaub-litb

10
litb : b를 평가하지 않고 연산자 && (a, b)에게 b를 전달하는 것은 불가능합니다. 컴파일러가 부작용이 없다고 보장 할 수 없기 때문에 b 평가를 취소 할 방법이 없습니다.
jmucchiello 2016 년

2
슬프다 나는 연산자 &&와 ||를 재정의해야한다고 생각했을 것입니다. 그리고 그들은 여전히 ​​완전히 결정 론적입니다 . 컴파일러는 그것을 감지하고 평가를 단락 상태로 유지합니다. 결국 순서는 관련이 없으며 부작용을 보장하지 않습니다!
Joe Pineda

2
@Joe : 그러나 반환 값과 연산자의 인수는 부울에서 다른 것으로 변경 될 수 있습니다. 3 가지 값 ( "true", "false"및 "unknown")으로 "특수"논리를 구현했습니다. 반환 값은 결정적이지만 단락 동작은 적절하지 않습니다.
Alex B

70

단락 평가 및 평가 순서는 C 및 C ++의 필수 의미 표준입니다.

그렇지 않은 경우 이와 같은 코드는 일반적인 관용구가 아닙니다.

   char* pChar = 0;
   // some actions which may or may not set pChar to something
   if ((pChar != 0) && (*pChar != '\0')) {
      // do something useful

   }

6.5.13 논리 AND 연산자 C99 사양 (PDF 링크)를 말한다

(4). 비트 이진 & 연산자와 달리 && 연산자는 왼쪽에서 오른쪽으로 평가합니다. 첫 번째 피연산자의 평가 후에 시퀀스 포인트가 있습니다. 첫 번째 피연산자가 0과 비교되면 두 번째 피연산자는 평가되지 않습니다.

마찬가지로 섹션 6.5.14 논리 OR 연산자

(4) 비트 단위와 달리 | 연산자, || 운영자는 좌우 평가를 보장합니다. 첫 번째 피연산자의 평가 후에 시퀀스 포인트가 있습니다. 첫 번째 피연산자가 0과 같지 않으면 두 번째 피연산자는 평가되지 않습니다.

C ++ 표준에서도 이와 유사한 문구를 찾을 수 있습니다 . 이 초안의 섹션 5.14를 확인하십시오 . 체커가 다른 답변에서 언급했듯이 && 또는 ||를 재정의하면 두 피연산자가 일반 함수 호출이 될 때 평가되어야합니다.


아, 내가 찾던 것! 따라서 ANSI-C 99에 따라 평가 순서 단락이 모두 의무화됩니다! 나는 거의 99 %이지만 ANSI-C ++에 대한 동등한 참조를보고 싶습니다.
Joe Pineda

C ++ 표준에 대한 무료 링크를 찾기가 어렵고 인터넷 검색에서 찾은 초안 사본에 연결했습니다.
Paul Dixon

POD 유형에 해당됩니다. 그러나 연산자 && 또는 연산자 || 이것들은 지름길이 아닙니다.
Martin York

1
그렇습니다. bool의 경우 항상 평가 순서 및 단락 동작을 보장합니다. 내장 된 두 가지 유형에 대해 operator &&를 오버로드 할 수 없기 때문입니다. 피연산자에 다른 동작을 수행하려면 하나 이상의 사용자 정의 유형이 필요합니다.
Johannes Schaub-litb

체커 와이 답변을 모두 수락 할 수 있기를 바랍니다. 나는 C ++에 주로 관심이 있기 때문에 다른 것을 받아들이고 있지만, 이것 역시 훌륭하다는 것을 인정해야합니다! 대단히 감사합니다!
Joe Pineda

19

그렇습니다 (평가 순서 및 단락 모두). 예제에서 모든 함수가 true를 반환하면 호출 순서는 functionA, functionB, functionC의 순서입니다. 이런 식으로 사용

if(ptr && ptr->value) { 
    ...
}

쉼표 연산자와 동일합니다.

// calls a, then b and evaluates to the value returned by b
// which is used to initialize c
int c = (a(), b()); 

하나는 왼쪽과 오른쪽의 피연산자 사이 말한다 &&, ||, ,및 첫번째 및 두번째 / 번째 피연산자 사이 ?:(조건 연산자)를 "시퀀스 점"이다. 해당 시점 이전에 모든 부작용이 완전히 평가됩니다. 따라서 이것은 안전합니다.

int a = 0;
int b = (a++, a); // b initialized with 1, and a is 1

쉼표 연산자를 사물을 구분하는 데 사용되는 구문 쉼표와 혼동하지 마십시오.

// order of calls to a and b is unspecified!
function(a(), b());

C ++ 표준은 다음과 5.14/1같이 말합니다 .

&& 연산자 그룹은 왼쪽에서 오른쪽입니다. 피연산자는 모두 암시 적으로 bool 유형으로 변환됩니다 (4 항). 두 피연산자가 모두 true이면 결과가 true이고, 그렇지 않으면 false입니다. &와 달리 &&는 왼쪽에서 오른쪽으로 평가합니다. 첫 번째 피연산자가 false 인 경우 두 번째 피연산자는 평가되지 않습니다.

그리고 5.15/1:

|| 운영자 그룹은 왼쪽에서 오른쪽으로. 피연산자는 모두 암시 적으로 부울로 변환됩니다 (4 항). 피연산자 중 하나가 true이면 true를, 그렇지 않으면 false를 반환합니다. |, ||와 달리 좌우 평가를 보장합니다. 또한 첫 번째 피연산자가 true로 평가되면 두 번째 피연산자는 평가되지 않습니다.

그것은 그 옆에 모두를 위해 말합니다 :

결과는 바보입니다. 임시 표현 (12.2)의 파괴를 제외한 첫 번째 표현의 모든 부작용은 두 번째 표현이 평가되기 전에 발생합니다.

그 외에도 1.9/18말한다

각 표현의 평가에서

  • a && b
  • a || b
  • a ? b : C
  • a , b

이 식 (5.14, 5.15, 5.16, 5.18)에서 연산자의 내장 의미를 사용하면 첫 번째 식을 평가 한 후 시퀀스 포인트가 있습니다.


10

오래된 K & R에서 직접 :

C 는 왼쪽에서 오른쪽으로 평가 &&되며 이를 보장합니다. ||곧 중요한 경우를 보게 될 것입니다.


3
K & R 2 판 p40. "&& 또는 ||로 연결된 표현은 왼쪽에서 오른쪽으로 평가되며 결과의 진실 또는 허위가 알려진 즉시 평가가 중단됩니다. 대부분의 C 프로그램은 이러한 특성에 의존합니다." 책에서 인용문을 찾을 수 없습니다. 이것은 매우 쓸모없는 1 판에서 나온 것입니까? 이 텍스트를 찾은 곳을 명확히하십시오.
Lundin

1
Ok는 이 고대 튜토리얼을 인용 하고 있습니다 . 1974 년부터별로 관련이 없습니다.
Lundin

6

매우 조심하십시오.

기본 유형의 경우 바로 가기 연산자입니다.

그러나 자신의 클래스 또는 열거 유형에 대해 이러한 연산자를 정의하면 바로 가기가 아닙니다. 이러한 서로 다른 상황에서 사용법의 의미 상 차이로 인해 이러한 연산자를 정의하지 않는 것이 좋습니다.

들어 operator &&operator ||평가 순서는 어려울 것 오른쪽 (그렇지 않으면 짧은 절단에 남아있는 기본적인 유형 :-) 그러나 만약 당신이 정의하는 것이 과부하 사업자, 이러한 따라서 기본적으로 구문 방법을 정의하는 설탕과 매개 변수의 평가입니다 순서입니다 찾으시는 주소가 없습니다.


1
연산자 오버로드는 POD 유형과 관계가 없습니다. 연산자 함수를 정의하려면 인수 중 하나 이상이 클래스 (또는 구조체 또는 공용체) 또는 열거 형이거나 그 중 하나에 대한 참조 여야합니다. POD가된다는 것은 memcpy를 사용할 수 있다는 것을 의미합니다.
Derek Ledbetter 2016 년

그리고 그것이 제가 말한 것입니다. 클래스에 &&를 오버로드하면 실제로 메서드 호출입니다. 따라서 매개 변수의 평가 순서에 의존 할 수 없습니다. 분명히 POD 유형에는 &&를 오버로드 할 수 없습니다.
Martin York

3
"POD 유형"이라는 용어를 잘못 사용하고 있습니다. 모든 구조체, 클래스, 공용체 또는 열거 형, POD에 대해 과부하 및 &를 할 수 있습니다. 양쪽이 숫자 유형이거나 포인터 인 경우 &&를 오버로드 할 수 없습니다.
Derek Ledbetter

나는 POD를 (당신이 말하고있는) POD가 아닌 (char / int / float 등)로 사용하고 있었고 보통 내장형이 아니라는 점에서 분리되거나 더 명시 적으로 언급됩니다.
Martin York

2
"기본 유형"을 의미했지만 "POD 유형"을 작성 했습니까?
Öö Tiib

0

귀하의 질문은 C ++ 연산자 우선 순위 와 연관성에 달려 있습니다. 기본적으로 여러 연산자가 있고 괄호가없는 표현식에서 컴파일러는 이러한 규칙에 따라 표현식 트리를 구성합니다.

우선,와 같은 A op1 B op2 C것이 있으면 항목을 (A op1 B) op2 C또는 로 그룹화 할 수 있습니다 A op1 (B op2 C). op1보다 우선 순위가 높은 경우 op2첫 번째 표현식이 표시됩니다. 그렇지 않으면 두 번째 것을 얻을 수 있습니다.

연관성을 위해, 같은 것을 A op B op C가졌을 때 다시 씬을 (A op B) op C또는 로 그룹화 할 수 A op (B op C)있습니다. op연관성을 남겼다 면 첫 번째 표현으로 끝납니다. 그것이 올바른 연관성을 가지고 있다면, 우리는 두 번째 것으로 끝납니다. 이것은 동일한 우선 순위 레벨의 연산자에도 적용됩니다.

이 특정 경우 &&보다 우선 순위가 높 ||으므로 식은 다음과 같이 평가됩니다.(a != "" && it == seqMap.end()) || isEven .

순서 자체는 표현식 트리 양식에서 "왼쪽에서 오른쪽"입니다. 먼저 평가 a != "" && it == seqMap.end()합니다. 그것이 사실이라면, 전체 표현이 사실이라면, 그렇지 않으면로갑니다 isEven. 절차는 물론 왼쪽 하위 표현 내에서 재귀 적으로 반복됩니다.


재미있는 음식이지만 우선 순위의 개념은 수학 표기법에 뿌리를두고 있습니다. 같은 일이 일어나는 a*b + c*보다 더 높은 우선 순위를 가지고 있습니다 +.

확실하지 않은 표현을 위해 훨씬 더 흥미롭고 모호한 A1 op1 A2 op2 ... opn-1 An모든 연산자가 동일한 우선 순위 우리가 형성 할 수있는 이진 표현식 트리의 수는 소위 카탈로니아 어 숫자에 의해 주어집니다 . 큰 경우 n, 이들은 매우 빠르게 성장합니다. 디


이 모든 것이 맞지만 평가 순서 및 단기 과금이 아니라 운영자 우선 순위와 연관성에 관한 것입니다. 그것들은 다릅니다.
Thomas Padron-McCarthy

0

Wikipedia를 신뢰하는 경우 :

[ &&||]는 비트 단위 연산자 & 및 | 결과를 왼쪽에서만 결정할 수 있으면 오른쪽 피연산자를 평가하지 않기 때문에

C (프로그래밍 언어)


11
표준이있을 때 위키를 신뢰해야하는 이유!
Martin York


C ++의 오버로드 된 연산자가 단락되지 않기 때문에 이것은 사실이지만 불완전합니다.
Thomas Padron-McCarthy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.