단락 논리 연산자가 필수입니까? 그리고 평가 순서?
는 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 논리 AND 연산자 C99 사양 (PDF 링크)를 말한다
(4). 비트 이진 & 연산자와 달리 && 연산자는 왼쪽에서 오른쪽으로 평가합니다. 첫 번째 피연산자의 평가 후에 시퀀스 포인트가 있습니다. 첫 번째 피연산자가 0과 비교되면 두 번째 피연산자는 평가되지 않습니다.
마찬가지로 섹션 6.5.14 논리 OR 연산자 는
(4) 비트 단위와 달리 | 연산자, || 운영자는 좌우 평가를 보장합니다. 첫 번째 피연산자의 평가 후에 시퀀스 포인트가 있습니다. 첫 번째 피연산자가 0과 같지 않으면 두 번째 피연산자는 평가되지 않습니다.
C ++ 표준에서도 이와 유사한 문구를 찾을 수 있습니다 . 이 초안의 섹션 5.14를 확인하십시오 . 체커가 다른 답변에서 언급했듯이 && 또는 ||를 재정의하면 두 피연산자가 일반 함수 호출이 될 때 평가되어야합니다.
그렇습니다 (평가 순서와 단락 모두). 예제에서 모든 함수가 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
:
The || operator groups left-to-right. The operands are both implicitly converted to bool (clause 4). It returns true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.
It says for both next to those:
The result is a bool. All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated.
In addition to that, 1.9/18
says
In the evaluation of each of the expressions
a && b
a || b
a ? b : C
a , b
using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression.
Straight from good old K&R:
C guarantees that
&&
and||
are evaluated left to right — we shall soon see cases where this matters.
Be very very careful.
For fundamental types these are shortcut operators.
But if you define these operators for your own class or enumeration types they are not shortcut. Because of this semantic difference in their usage under these different circumstances it is recommended that you do not define these operators.
For the operator &&
and operator ||
for fundamental types the evaluation order is left to right (otherwise short cutting would be hard :-) But for overloaded operators that you define, these are basically syntactic sugar to defining a method and thus the order of evaluation of the parameters is undefined.
Your question comes down to C++ operator precedence and associativity. Basically, in expressions with multiple operators and no parentheses, the compiler constructs the expression tree by following these rules.
For precedence, when you have something like A op1 B op2 C
, you could group things as either (A op1 B) op2 C
or A op1 (B op2 C)
. If op1
has higher precedence than op2
, you'll get the first expression. Otherwise, you'll get the second one.
For associativity, when you have something like A op B op C
, you could again group thins as (A op B) op C
or A op (B op C)
. If op
has left associativity, we end up with the first expression. If it has right associativity, we end up with the second one. This also works for operators at the same precedence level.
In this particular case, &&
has higher precedence than ||
, so the expression will be evaluated as (a != "" && it == seqMap.end()) || isEven
.
The order itself is "left-to-right" on the expression-tree form. So we'll first evaluate a != "" && it == seqMap.end()
. If it's true the whole expression is true, otherwise we go to isEven
. The procedure repeats itself recursively inside the left-subexpression of course.
Interesting tidbits, but the concept of precedence has its roots in mathematic notation. The same thing happens in a*b + c
, where *
has higher precedence than +
.
Even more interesting/obscure, for a unparenthasiszed expression A1 op1 A2 op2 ... opn-1 An
, where all operators have the same precedence, the number of binary expression trees we could form is given by the so called Catalan numbers. For large n
, these grow extremely fast. d
If you trust Wikipedia:
[
&&
and||
] are semantically distinct from the bit-wise operators & and | because they will never evaluate the right operand if the result can be determined from the left alone
'programing tip' 카테고리의 다른 글
ORA-00979 표현에 의한 그룹이 아닙니다 (0) | 2020.06.24 |
---|---|
콘센트를 반복 콘텐츠 iOS에 연결할 수 없습니다 (0) | 2020.06.24 |
현재 Git에서 체크 아웃 된 커밋 찾기 (0) | 2020.06.24 |
Go로 시작하는 기능이 없습니까? (0) | 2020.06.24 |
c # /. net에서 예외를 문서화하는 방법 (0) | 2020.06.24 |