단락 논리 연산자가 의무화되어 있습니까? 그리고 평가 순서?
-
06-07-2019 - |
문제
ANSI 표준입니다 위임 논리 연산자는 C 또는 C ++에서 단락되어야합니까?
나는 당신의 코드 가이 작업이 짧은 회로에 의존해서는 안된다는 K & R 책을 기억하기 때문에 혼란스러워합니다. 누군가가 표준에서 논리 작전이 항상 단락 된 위치를 지적 할 수 있습니까? 나는 주로 C ++에 관심이 있습니다. C에 대한 답변도 좋을 것입니다.
또한 평가 순서가 엄격하게 정의되지 않았다는 것을 읽지 않으므로 코드 내에서 함수가 특정 순서로 의존하지 않거나 가정하지 않아야합니다. 진술의 끝까지 모든 참조 된 함수 호출되었지만 컴파일러는 가장 효율적인 순서를 선택할 수있는 자유가 있습니다.
표준은이 표현의 평가 순서를 나타 냅니까?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
해결책
예, 운영자에게는 단락 및 평가 순서가 필요합니다. ||
그리고 &&
C 및 C ++ 표준 모두에서.
C ++ 표준은 말합니다 (C 표준에는 동등한 조항이 있어야 함) :
1.9.18
다음 표현의 평가에서
a && b a || b a ? b : c a , b
이 표현에서 연산자의 내장 의미를 사용하고 첫 번째 표현식의 평가 후 시퀀스 지점이 있습니다. (12).
C ++에는 추가 함정이 있습니다. 단락이 있습니다. 아니다 오퍼레이터를 과부하시키는 유형에 적용하십시오 ||
그리고 &&
.
각주 12 :이 단락에 표시된 연산자는 5 항에 설명 된 바와 같이 내장 연산자입니다.이 연산자 중 하나가 유효한 컨텍스트에서 과부하 (13 항)가 사용자 정의 연산자 함수를 지정하면 표현이 지정된 표현이 지정됩니다. 기능 호출 및 오페라는 인수 목록을 형성합니다. 그들 사이에 묵시적 시퀀스 지점이 없다.
매우 구체적인 요구 사항이 없다면 일반적으로 이러한 연산자를 C ++에 과부하하는 것이 좋습니다. 이를 수행 할 수는 있지만 다른 연산자 가이 연산자를 과부하시키는 유형으로 인스턴스화하는 템플릿을 통해 간접적으로 사용되는 경우 다른 사람들의 코드에서 예상되는 동작을 중단 할 수 있습니다.
다른 팁
단락 평가 및 평가 순서는 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 논리 및 연산자 C99 사양의 (PDF 링크) 말한다
(4). Bitwise Binary & Operator와 달리 && 운영자는 왼쪽에서 오른쪽으로 평가를 보장합니다. 첫 번째 피연산자 평가 후 시퀀스 지점이 있습니다. 첫 번째 피연산자가 0과 동일하면 두 번째 피연산자는 평가되지 않습니다.
마찬가지로, 섹션 6.5.14 논리 또는 연산자 말한다
(4) 비트와 달리 | 연산자, || 운영자는 왼쪽에서 오른쪽으로 평가를 보장합니다. 첫 번째 피연산자 평가 후 시퀀스 지점이 있습니다. 첫 번째 피연산자가 0과 비교 한 경우, 두 번째 피연산자는 평가되지 않습니다.
C ++ 표준에서도 비슷한 문구를 찾을 수 있습니다. 이 초안 사본에서 섹션 5.14를 확인하십시오. Checkers가 다른 답변에 기록한 것처럼, && 또는 ||를 재정의하는 경우, 두 피연산자는 정기적 인 기능 호출이되므로 평가되어야합니다.
그렇습니다. (평가 순서와 단락 모두). 예제에서 모든 함수가 true를 반환하면 호출 순서는 functiona에서 엄격하게 functionb에서 function으로 이어집니다. 이런 식으로 사용됩니다
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 항)으로 변환됩니다. 두 피연산자가 모두 참이고 그렇지 않으면 결과는 사실입니다. &, &&와 달리 왼쪽에서 오른쪽으로 평가합니다. 첫 번째 피연산자가 False 인 경우 두 번째 피연산자는 평가되지 않습니다.
그리고에서 5.15/1
:
|| 운영자 그룹은 왼쪽에서 오른쪽으로 그룹화합니다. 피연산자는 모두 암시 적으로 bool로 변환됩니다 (4 항). 피연산자 중 하나가 참이면 사실이 반환되고 그렇지 않으면 거짓이됩니다. |, ||와 달리 왼쪽에서 오른쪽으로의 평가를 보장합니다. 또한, 제 1 피연산자가 True로 평가되면 두 번째 피연산자는 평가되지 않습니다.
그것은 그 옆에 다음과 같이 말합니다.
결과는 bool입니다. 두 번째 표현이 평가되기 전에 임시 (12.2)의 파괴를 제외한 첫 번째 표현의 모든 부작용은 발생합니다.
그 외에도 1.9/18
말한다
각 표현의 평가에서
a && b
a || b
a ? b : C
a , b
이 표현식에서 연산자의 내장 의미 (5.14, 5.15, 5.16, 5.18)를 사용하면 첫 번째 표현식을 평가 한 후 시퀀스 지점이 있습니다.
좋은 오래된 K & R에서 바로 :
C를 보장합니다
&&
그리고||
왼쪽에서 오른쪽으로 평가됩니다. 곧 이것이 중요한 경우를 보게 될 것입니다.
매우 조심하십시오.
기본 유형의 경우 바로 가기 연산자입니다.
그러나이 연산자를 자신의 클래스 또는 열거 유형에 대해 정의하면 바로 가기가 아닙니다. 이러한 다른 상황에서 사용의 의미 차이로 인해 이러한 연산자를 정의하지 않는 것이 좋습니다.
용 operator &&
그리고 operator ||
기본 유형의 경우 평가 순서가 왼쪽에서 오른쪽으로 오른쪽으로 나타납니다 (그렇지 않으면 단락은 어렵습니다 :-) 그러나 정의하는 과부하 된 연산자의 경우 기본적으로 방법을 정의하는 데있어 구문 설탕이므로 매개 변수의 평가 순서가 정의되지 않았습니다.
위키 백과를 신뢰한다면 :
[
&&
그리고||
]는 비트 현행 운영자와 의미 적으로 구별됩니다. 결과가 왼쪽에서 단독으로 결정될 수있는 경우 오른쪽 피연산자를 평가하지 않기 때문입니다.
http://en.wikipedia.org/wiki/c_(programming_language)#characteristics
당신의 질문은 이어집니다 C ++ 연산자 우선 순위 그리고 연관성. 기본적으로, 여러 연산자와 괄호가없는 표현식에서, 컴파일러는이 규칙에 따라 표현식 트리를 구성합니다.
우선 순위에, 당신이 같은 것이있을 때 A op1 B op2 C
, 당신은 물건을 그룹화 할 수 있습니다 (A op1 B) op2 C
또는 A op1 (B op2 C)
. 만약에 op1
보다 우선 순위가 높습니다 op2
, 당신은 첫 번째 표현을 얻을 수 있습니다. 그렇지 않으면 두 번째를 얻을 수 있습니다.
연관성을 위해, 당신이 같은 것을 가지고있을 때 A op B op C
, 당신은 다시 Thins를 그대로 그룹화 할 수있었습니다 (A op B) op C
또는 A op (B op C)
. 만약에 op
연관성을 남겼습니다. 우리는 첫 번째 표현으로 끝납니다. 그것이 올바른 연관성을 가지고 있다면, 우리는 두 번째로 끝납니다. 이것은 또한 동일한 우선 순위 수준의 운영자에게도 작동합니다.
이 특별한 경우 &&
보다 우선 순위가 높습니다 ||
, 표현은 다음과 같이 평가 될 것입니다 (a != "" && it == seqMap.end()) || isEven
.
순서 자체는 표현식 트리 형태의 "왼쪽에서 오른쪽"입니다. 그래서 우리는 먼저 평가할 것입니다 a != "" && it == seqMap.end()
. 그것이 사실이라면 전체 표현이 사실입니다. 그렇지 않으면 우리는 isEven
. 이 절차는 물론 왼쪽-서블 프레스 내부에서 재귀 적으로 반복됩니다.
흥미로운 tidbits이지만 우선 순위의 개념은 수학 표기법에 뿌리를두고 있습니다. 같은 일이 발생합니다 a*b + c
, 어디 *
보다 우선 순위가 높습니다 +
.
더 흥미롭고 모호한, 불안정한 표현을 위해 A1 op1 A2 op2 ... opn-1 An
, 모든 연산자가 동일한 우선 순위를 갖는 경우, 우리가 형성 할 수있는 이진 발현 트리의 수는 소위 호출에 의해 주어집니다. 카탈로니아어 번호. 큰 경우 n
, 이것들은 매우 빠르게 자랍니다. 디