왜 &&
바람직 &
하고 ||
바람직 |
합니까?
나는 수년간 프로그래밍을 해 온 누군가에게 물었고 그의 설명은 다음과 같습니다.
예를 들어,에 if (bool1 && bool2 && bool3) { /*DoSomething*/ }
, bool1
시험에 대한 진실이어야 bool2
로 이동하기 전에 사실로 가지고 bool3
내가 하나를 사용했던 경우 등, &
대신 그들 모두에 충실 할 경우에도 시험에는 순서가 없다 다음 줄로 나아가면 어쨌든 중요한가요?
참고 : 나는 유아와 동등한 프로그래밍이고 이것은 심각하거나 긴급한 질문이 아니라는 것을 지적하고 싶습니다. 왜 일이 다른 사람과 반대로 특정 방식으로 이루어져야 하는지를 이해하는 것이 더 중요합니다.
답변
대부분의 경우, &&
및 ||
이상 선호 &
하고 |
이전하기 때문에 평가는 즉시 결과를 알 수있는 바와 같이 취소 즉, 단락이다.
예:
if(CanExecute() && CanSave())
{
}
CanExecute
반환 하면 의 반환 값에 관계없이 false
전체 표현식이됩니다 . 이 때문에 실행되지 않습니다.false
CanSave
CanSave
이것은 다음과 같은 상황에서 매우 편리합니다.
string value;
if(dict.TryGetValue(key, out value) && value.Contains("test"))
{
// Do Something
}
TryGetValue
false
제공된 키가 사전에 없으면를 반환 합니다. 때문에의 단락 특성 &&
, value.Contains("test")
경우에만 실행됩니다 TryGetValue
반환 true
따라서와는 value
아닙니다 null
. 비트 AND 연산자를 &
대신 사용 NullReferenceException
하면 식의 두 번째 부분이 실행되므로 사전에 키를 찾을 수 없으면 if가 표시됩니다.
이와 비슷하지만 더 간단한 예는 다음 코드입니다 (TJHeuvel에서 언급 한대로).
if(op != null && op.CanExecute())
{
// Do Something
}
CanExecute
이 op
아닌 경우에만 실행됩니다 null
. 경우 op
이며 null
, 식의 첫 번째 부분은 ( op != null
)로 평가 false
하고, 나머지의 평가 ( op.CanExecute()
) 스킵된다.
이 외에도에서은, 기술적으로, 그들도, 다른 :
&&
및 ||
에서만 사용할 수있는 bool
반면, &
및 |
모든 정수 계열 형식 (사용할 수 있습니다 bool
, int
, long
, sbyte
그들이 비트 연산자이기 때문에, …). &
는 IS 비트 AND 연산자와 |
는 IS 비트 OR 연산자.
매우 정확하게 말하자면 C #에서 이러한 연산자 ( &
, |
[및 ^
])를 “논리 연산자”라고합니다 ( C # 사양 , 장 7.11 참조). 이러한 연산자에는 여러 가지 구현이 있습니다.
- 정수의 (
int
,uint
,long
와ulong
, 제 7.11.1)
들은 피연산자 오퍼레이터의 비트 결과를 계산하도록 구현되고, 즉,&
비트 단위 논리 계산하도록 구현이다AND
등등 - 열거 형의 경우 (7.11.2 장) :
기본 형식의 열거 형의 논리적 작업을 수행하도록 구현됩니다. - 부울 및 널 입력 가능 부울 (7.11.3 및 7.11.4 장)의 경우 :
비트 단위 계산을 사용하여 결과가 계산되지 않습니다. 결과는 가능성이 너무 적기 때문에 기본적으로 두 피연산자의 값을 기반으로 조회됩니다.
두 값 모두 조회에 사용되므로이 구현은 단락되지 않습니다.
답변
이것이 의미하는 바를 명확하게 설명하기 위해 (다른 답변이 암시하더라도-아마도 이해하지 못하는 용어를 사용하십시오).
다음 코드 :
if (a && b)
{
Foo();
}
실제로 이것으로 컴파일됩니다 :
if (a)
{
if (b)
{
Foo();
}
}
다음 코드는 표시된 그대로 정확하게 컴파일됩니다.
if (a & b)
{
Foo();
}
이것을 단락이라고합니다. 일반적으로 항상 &&
그리고 ||
귀하의 조건에서 사용해야 합니다.
보너스 마크 : 하지 말아야 할 한 가지 시나리오가 있습니다. 만약 성능이 결정적인 상황에 있다면 (이것은 나노초 결정적입니다 ) 단락 null
은 분기 / 점프이므로 반드시 (예 : 점검) 단락을 사용하십시오 . CPU에서 분기 오류가 발생할 수 있습니다. 는 &
보다 훨씬 저렴합니다 &&
. 단락이 실제로 논리를 깰 수있는 시나리오도 있습니다 . 이 답변 을 살펴보십시오 .
Diatribe / Monologue : 가장 행복하게 무시하는 가지 잘못 예측에 대해 Andy Firth 인용 (13 년 동안 게임을해온 사람) : “이것은 사람들이 갈 필요가 있다고 생각하는 수준이 낮을 수 있지만 잘못되었을 것입니다. 프로그래밍하는 하드웨어가 지점을 어떻게 처리 할 수 있는지 이해 대부분의 프로그래머가 re : death of a 1,000 cuts보다 훨씬 더 감사 할 것입니다. “
- 게임 개발자 (및 극단적 인 실시간 조건에서 작업하는 다른 사람들)는 예측 변수에 더 적합하도록 논리를 재구성하는 것까지 진행합니다. 디 컴파일 된 mscorlib 코드에도 이러한 증거가 있습니다.
- .NET이 이러한 유형의 것을 차단한다고해서 중요하지 않다는 의미는 아닙니다. 브랜치 잘못 예측은 60Hz에서 엄청나게 비싸다. 또는 10,000 요청 / 초
- 인텔은 잘못된 예측 위치를 식별 할 수있는 도구가 없거나 Windows에 이에 대한 성능 카운터가 없거나 문제를 설명 할 단어가 없습니다.
- 낮은 수준과 아키텍처에 대한 무지가 자신을 잘 아는 사람을 만들지는 않습니다.
- 작업중인 하드웨어의 한계를 항상 이해하십시오.
다음은 비신자에 대한 벤치 마크입니다. https://gist.github.com/1200737에 영향을 미치는 스케줄러를 완화하기 위해 RealTime / High에서 프로세스를 실행하는 것이 가장 좋습니다.
답변
논리 연산자 ( ||
및 &&
)와 비트 연산자 ( |
및 &
).
논리 연산자와 비트 연산자의 가장 중요한 차이점은 논리 연산자는 두 개의 부울을 취하고 부울을 생성하는 반면 비트 연산자는 두 개의 정수를 취하고 정수를 생성한다는 것입니다 (참고 : 정수는 int뿐만 아니라 모든 정수 데이터 유형을 의미 함).
반복적으로 비트 단위 연산자는 비트 패턴 (예 : 01101011)을 가져와 각 비트에서 비트 단위 AND / OR을 수행합니다. 예를 들어 두 개의 8 비트 정수가있는 경우 :
a = 00110010 (in decimal: 32+16+2 = 50)
b = 01010011 (in decimal: 64+ 16+2+1 = 83)
----------------
a & b = 00010010 (in decimal: 16+2 = 18)
a | b = 01110011 (in decimal: 64+32+16+2+1 = 115)
논리 연산자는 다음에서만 작동합니다 bool
.
a = true
b = false
--------------
a && b = false
a || b = true
둘째, true와 false가 각각 1과 0과 같기 때문에 bool에서 비트 연산자를 사용하는 것이 종종 가능하며, true를 1로 변환하고 0을 0으로 변환하면 비트 연산을 수행 한 다음 0이 아닌 값을 변환합니다 true로, 0에서 false로; 논리 연산자를 방금 사용한 경우 결과가 동일하게됩니다 (연습을 위해 이것을 점검하십시오).
또 다른 중요한 차이점은 논리 연산자가 단락 되었다는 것 입니다. 따라서 일부 서클에서 [1] 사람들은 종종 다음과 같은 일을하는 것을 보게됩니다.
if (person && person.punch()) {
person.doVictoryDance()
}
어떤로 변환 : “사람이 (즉, null이 아닌)이있는 경우, 그에게 / 그녀에게 펀치를 시도하고 펀치가 (사실 즉, 반환) 성공하면, 다음 승리의 춤을” .
비트 연산자를 대신 사용했다면 다음과 같습니다.
if (person & person.punch()) {
person.doVictoryDance()
}
에 변환합니다 : “사람이 존재하는 경우 (즉, null이 아닌)과 펀치 (사실, 즉 반환), 다음 승리의 춤을 성공한다” .
단락 된 논리 연산자에서 널 (null) 인 person.punch()
경우 코드가 전혀 실행되지 않을 수 있습니다 person
. 실제로,이 특정한 경우, 두 번째 코드는 사람이 null인지 여부에 관계없이 person
호출하려고하기 때문에 널 (null) 인 경우 널 참조 오류를 생성합니다 person.punch()
. 올바른 피연산자를 평가하지 않는 이러한 동작을 단락 이라고 합니다.
[1] 일부 프로그래머는 부작용이있는 함수 호출을 if
표현식 안에 넣는 것에 대해 혼란 스러울 수 있지만, 다른 프로그래머에게는 일반적이고 유용한 관용구입니다.
비트 연산자는 한 번에 32 비트에서 작동하기 때문에 (32 비트 시스템을 사용하는 경우), 예를 들어, 여러 조건을 비교해야하는 경우보다 우아하고 빠른 코드로 이어질 수 있습니다.
int CAN_PUNCH = 1 << 0, CAN_KICK = 1 << 1, CAN_DRINK = 1 << 2, CAN_SIT = 1 << 3,
CAN_SHOOT_GUNS = 1 << 4, CAN_TALK = 1 << 5, CAN_SHOOT_CANNONS = 1 << 6;
Person person;
person.abilities = CAN_PUNCH | CAN_KICK | CAN_DRINK | CAN_SIT | CAN_SHOOT_GUNS;
Place bar;
bar.rules = CAN_DRINK | CAN_SIT | CAN_TALK;
Place military;
military.rules = CAN_SHOOT_CANNONS | CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT;
CurrentLocation cloc1, cloc2;
cloc1.usable_abilities = person_abilities & bar_rules;
cloc2.usable_abilities = person_abilities & military_rules;
// cloc1.usable_abilities will contain the bit pattern that matches `CAN_DRINK | CAN_SIT`
// while cloc2.usable_abilities will contain the bit pattern that matches `CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT`
논리 연산자를 사용하여 동일한 작업을 수행하려면 어색한 비교가 필요합니다.
Person person;
person.can_punch = person.can_kick = person.can_drink = person.can_sit = person.can_shoot_guns = true;
person.can_shoot_cannons = false;
Place bar;
bar.rules.can_drink = bar.rules.can_sit = bar.rules.can_talk = true;
bar.rules.can_punch = bar.rules.can_kick = bar.rules.can_shoot_guns = bar.rules.can_shoot_cannons = false;
Place military;
military.rules.can_punch = military.rules.can_kick = military.rules.can_shoot_guns = military.rules.can_shoot_cannons = military.rules.can_sit = true;
military.rules.can_drink = military.rules.can_talk = false;
CurrentLocation cloc1;
bool cloc1.usable_abilities.can_punch = bar.rules.can_punch && person.can_punch,
cloc1.usable_abilities.can_kick = bar.rules.can_kick && person.can_kick,
cloc1.usable_abilities.can_drink = bar.rules.can_drink && person.can_drink,
cloc1.usable_abilities.can_sit = bar.rules.can_sit && person.can_sit,
cloc1.usable_abilities.can_shoot_guns = bar.rules.can_shoot_guns && person.can_shoot_guns,
cloc1.usable_abilities.can_shoot_cannons = bar.rules.can_shoot_cannons && person.can_shoot_cannons
cloc1.usable_abilities.can_talk = bar.rules.can_talk && person.can_talk;
bool cloc2.usable_abilities.can_punch = military.rules.can_punch && person.can_punch,
cloc2.usable_abilities.can_kick = military.rules.can_kick && person.can_kick,
cloc2.usable_abilities.can_drink = military.rules.can_drink && person.can_drink,
cloc2.usable_abilities.can_sit = military.rules.can_sit && person.can_sit,
cloc2.usable_abilities.can_shoot_guns = military.rules.can_shoot_guns && person.can_shoot_guns,
cloc2.usable_abilities.can_talk = military.rules.can_talk && person.can_talk,
cloc2.usable_abilities.can_shoot_cannons = military.rules.can_shoot_cannons && person.can_shoot_cannons;
비트 패턴과 비트 연산자가 사용되는 전형적인 예는 Unix / Linux 파일 시스템 권한입니다.
답변
다음의 경우 :
if (obj != null && obj.Property == true) { }
예상대로 작동합니다.
그러나:
if (obj != null & obj.Property == true) { }
잠재적으로 null 참조 예외가 발생할 수 있습니다.
답변
짧고 간단한
1 && 2
= TRUE
때문에
1 = 참 (비 – 제로) C에서
2 = 참 (비 – 제로)에서 C
true
ANDS 논리적으로 true
에주고 true
.
그러나
1 & 2
이진에서 1 = 0001
2 이진에서 0010
이므로 = 0 = false
0001 AND는 0010과 비트 단위로 10 진수로 0000 = 0을 제공합니다.
마찬가지로 || 와 | 연산자도 …!
답변
&&
의 단락 버전입니다 &
.
우리가 평가 false & true
하고 있다면 , 우리는 이미 결과가 거짓이라는 첫 번째 주장을 살펴 보는 것을 알고 있습니다. &&
운영자의 버전은 전체 표현식을 평가하는 것이 아니라, 즉시이 할 수있는 결과를 반환합니다. |
연산자 의 유사한 버전도 있습니다 ||
.
답변
if (list.Count() > 14 && list[14] == "foo")
는 안전하다
if (list.Count() > 14 & list[14] == "foo")
목록의 크기가 맞지 않으면 충돌이 발생합니다.