예, 이것은 숙제 질문이지만 주제에 대해 조사하고 상당한 양의 깊이 생각을했지만 이것을 이해할 수 없습니다. 질문은이 코드 조각이 단락 동작을 나타내지 않으며 그 이유를 묻습니다. 그러나 그것은 단락 동작을 보이는 것처럼 보이므로 누군가가 왜 그렇지 않은지 설명 할 수 있습니까?
C에서 :
int sc_and(int a, int b) {
return a ? b : 0;
}
이 경우에 저에게 보이는 a
거짓, 프로그램 평가하려고하지 않습니다 b
전혀하지만, 내가 잘못해야합니다. b
이 경우 프로그램이 터치하지 않아도되는 이유는 무엇 입니까?
답변
이것은 속임수 질문입니다. 메서드에 b
대한 입력 인수 sc_and
이므로 항상 평가됩니다. 다른 단어에서는 sc_and(a(), b())
호출 a()
하고 호출 한 다음 b()
(순서는 보장되지 않음) sc_and
결과 를 호출 a(), b()
하여 a?b:0
. 절대적으로 단락되는 삼항 연산자 자체와는 관련이 없습니다.
최신 정보
내가 이것을 ‘속임수 질문’이라고 부르는 이유와 관련하여 : ‘단락’을 고려할 위치에 대한 잘 정의 된 컨텍스트가 부족하기 때문입니다 (적어도 OP에 의해 재현 됨). 함수 정의 만 주어 졌을 때 많은 사람들 은 질문의 맥락 이 함수 의 본문 에 대해 묻는다고 가정 합니다 . 그들은 종종 그 기능을 그 자체로 표현으로 간주하지 않습니다. 이것이 질문의 ‘속임수’입니다. 일반적으로 프로그래밍에서, 특히 규칙에 대한 많은 예외가있는 C와 같은 언어에서는 그렇게 할 수 없다는 것을 상기시키기 위해. 예를 들어 질문이 다음과 같이 요청 된 경우 :
다음 코드를 고려하십시오. main 에서 호출 될 때 sc_and exibit 단락 동작을 수행합니다 .
int sc_and(int a, int b){
return a?b:0;
}
int a(){
cout<<"called a!"<<endl;
return 0;
}
int b(){
cout<<"called b!"<<endl;
return 1;
}
int main(char* argc, char** argv){
int x = sc_and(a(), b());
return 0;
}
sc_and
자신의 도메인 특정 언어 에서 그 자체로 운영자로 생각 하고 호출 sc_and
이 일반처럼 단락 동작 을 나타내는 지&&
평가 해야한다는 것이 즉시 분명 해질 것 입니다. 삼항 연산자에 초점을 맞추지 않고 대신 C / C ++의 함수 호출 메커니즘에 초점을 맞춰야한다는 것이 분명하기 때문에 트릭 질문이라고 생각하지 않습니다. sc_and
단락 을 수행하는 후속 질문에 멋지게 작성하십시오 #define
. 이는 함수 가 아닌 사용을 포함 합니다).
삼항 연산자 자체가 단락 (또는 ‘조건부 평가’와 같은 다른 것)을 수행하는 것을 호출할지 여부는 단락에 대한 정의에 따라 다르며 이에 대한 다양한 의견을 읽을 수 있습니다. 내 생각에는 그렇지만 실제 질문이나 내가 ‘트릭’이라고 부르는 이유와는별로 관련이 없습니다.
답변
성명서
bool x = a && b++; // a and b are of int type
실행하는, b++
피연산자 경우 평가되지 a
로 평가 false
(단락 동작). 이는 부작용이 발생 b
하지 않음을 의미합니다 .
이제 함수를 살펴보십시오.
bool and_fun(int a, int b)
{
return a && b;
}
그리고 이것을 불러
bool x = and_fun(a, b++);
이 경우, 여부 a
입니다 true
또는 false
, b++
항상 평가됩니다 1 에 함수 호출 및 부작용 중 b
항상 일어날 것이다.
같은 사실입니다
int x = a ? b : 0; // Short circuit behavior
과
int sc_and (int a, int b) // No short circuit behavior.
{
return a ? b : 0;
}
1 함수 인수의 평가 순서가 지정되지 않았습니다.
답변
이미 다른 사람들이 지적했듯이, 두 인수로 함수에 전달되는 것이 무엇이든 전달되는대로 평가됩니다. 이것이 테너 리 연산 이전의 방식입니다.
반면에 이것은
#define sc_and(a, b) \
((a) ?(b) :0)
것 이로, “단락” 매크로 함수 호출이와 함수의 인수없이 평가 (들) 수행을 의미하지는 않습니다.
답변
@cmasters 주석에 명시된 오류를 수정하도록 편집되었습니다.
에
int sc_and(int a, int b) {
return a ? b : 0;
}
… return
ed 표현식은 단락 평가를 나타내지 만 함수 호출은 그렇지 않습니다.
전화 해보세요
sc_and (0, 1 / 0);
함수 호출 1 / 0
은 사용되지 않지만 평가 하므로 0으로 나누기 오류가 발생할 수 있습니다.
ANSI C 표준 (초안)에서 발췌 한 관련 내용은 다음과 같습니다.
2.1.2.3 프로그램 실행
…
추상 기계에서 모든 표현식은 의미 체계에 지정된대로 평가됩니다. 실제 구현은 해당 값이 사용되지 않고 필요한 부작용이 발생하지 않는다고 추론 할 수있는 경우 표현식의 일부를 평가할 필요가 없습니다.
과
3.3.2.2 함수 호출
….
의미론
…
함수 호출을 준비 할 때 인수가 평가되고 각 매개 변수에 해당 인수의 값이 할당됩니다.
내 생각 엔 각 인수는 전체 인수 목록이라고 표현으로 평가되지만 있다는 것입니다 하지 따라서 비 SCE 동작은 필수입니다, 식.
C 표준의 심해 표면에 대한 스 플래셔로서 저는 두 가지 측면에 대한 적절한 정보에 감사드립니다.
- 평가
1 / 0
가 정의되지 않은 동작을 생성 합니까 ? - 인수 목록이 표현식입니까? (나는 그렇게 생각하지 않는다)
추신
C ++로 이동 sc_and
하고 inline
함수 로 정의하더라도 SCE를 얻지 못합니다 . @alk 처럼 C 매크로로 정의 하면 확실히 그렇게 될 것입니다.
답변
삼항 연산 단락을 명확하게 보려면 정수 대신 함수 포인터를 사용하도록 코드를 약간 변경해보십시오.
int a() {
printf("I'm a() returning 0\n");
return 0;
}
int b() {
printf("And I'm b() returning 1 (not that it matters)\n");
return 1;
}
int sc_and(int (*a)(), int (*b)()) {
a() ? b() : 0;
}
int main() {
sc_and(a, b);
return 0;
}
그런 다음 컴파일하십시오 (거의 최적화 없이도 : -O0
!). 당신은 볼 b()
경우 실행되지 않습니다 a()
반환 거짓.
% gcc -O0 tershort.c
% ./a.out
I'm a() returning 0
%
생성 된 어셈블리는 다음과 같습니다.
call *%rdx <-- call a()
testl %eax, %eax <-- test result
je .L8 <-- skip if 0 (false)
movq -16(%rbp), %rdx
movl $0, %eax
call *%rdx <- calls b() only if not skipped
.L8:
따라서 다른 사람들이 올바르게 지적했듯이 질문 트릭은 단락하지 않는 호출 (값별 호출)에 대한 매개 변수 평가 대신 단락 ( ‘조건부 평가’라고 함)을 수행하는 삼항 연산자 동작에 초점을 맞추도록하는 것입니다.
답변
C 삼항 연산자는 값이 반환 될 수있는 경우 표현식 b 및 c가 제공하는 값을 결정하기 위해 단일 표현식 a (조건) 만 평가하므로 단락 할 수 없습니다 .
다음 코드 :
int ret = a ? b : c; // Here, b and c are expressions that return a value.
다음 코드와 거의 동일합니다.
int ret;
if(a) {ret = b} else {ret = c}
표현식 a 는 && 또는 ||와 같은 다른 연산자로 구성 될 수 있습니다. 값을 반환하기 전에 두 개의 표현식을 평가할 수 있기 때문에 단락 될 수 있지만 단락을 수행하는 삼항 연산자로 간주되지 않고 일반 if 문에서와 같이 조건에서 사용되는 연산자로 간주됩니다.
최신 정보:
삼항 연산자가 단락 연산자라는 논쟁이 있습니다. 인수는 모든 피연산자를 평가하지 않는 모든 연산자가 아래 주석의 @aruisdante에 따라 단락을 수행한다고 말합니다. 이 정의가 주어지면 삼항 연산자가 단락되고 이것이 원래 정의 인 경우 동의합니다. 문제는 “단락 (short-circuit)”이라는 용어가 원래 이러한 동작을 허용하는 특정 종류의 연산자에 사용되었으며 논리 / 부울 연산자이며 그 이유 만 설명하려고한다는 것입니다.
문서 다음 단락 평가 , 단락 평가는 첫 번째 피연산자가 첫 번째 피연산자 인 && 연산자, 이것이 두 번째 무관 할 것으로 알고있는 방식으로 언어로 구현 부울 연산자 칭한다 거짓 , 그리고 || 연산자는 첫 번째 피연산자 true 이며 C11 사양 은 6.5.13 논리 AND 연산자 및 6.5.14 논리 OR 연산자에서도이를 기록합니다.
즉, 단락 동작을 식별하려면 첫 번째 피연산자가 두 번째 피연산자와 관련이없는 경우 부울 연산자처럼 모든 피연산자를 평가해야하는 연산자에서이를 식별해야합니다. 이는 단락이 논리 연산자에서 발생하기 때문에 MathWorks 의 “논리적 단락”섹션에서 단락에 대한 다른 정의에 기록 된 내용과 일치 합니다.
내가 삼항 연산자라고도하는 C 삼항 연산자를 설명하려고했지만 피연산자 중 두 개만 평가하고 첫 번째 피연산자를 평가 한 다음 두 번째 피연산자를 평가합니다. 첫 번째. 항상 이렇게합니다. 어떤 상황에서도이 세 가지를 모두 평가해서는 안되므로 어떤 경우에도 “단락”이 없습니다.
항상 그렇듯이, 무언가가 옳지 않다는 것을 알게된다면, 단지 반대표가 아니라 이에 반대하는 의견을 적어주세요. 이것은 단지 SO 경험을 더 악화시킬뿐입니다. 그리고 저는 우리가 단지 대답 만하는 훨씬 더 나은 커뮤니티가 될 수 있다고 믿습니다. 하나는 동의하지 않습니다.