programing

C의 이 논리 AND 버전이 단락 동작을 나타내지 않는 이유는 무엇입니까?

newsource 2022. 8. 1. 22:50

C의 이 논리 AND 버전이 단락 동작을 나타내지 않는 이유는 무엇입니까?

네, 이건 숙제 질문이지만, 저는 이 주제에 대해 조사와 깊은 생각을 해봤는데, 이것을 이해할 수 없어요.이 질문에서는 이 코드 조각이 단락 동작을 나타내지 않으며 그 이유를 묻습니다.하지만 제가 보기엔 그게 단락 행동을 보이는 것 같은데, 왜 그렇지 않은지 누가 설명해 줄 수 있나요?

C:

int sc_and(int a, int b) {
    return a ? b : 0;
}

가 이 경우, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.a.프로그램은 평가하려고 하지 않습니다.b혀혀 、 하지 、 봐봐렸봐봐 。은 왜 '만져도'를 터치하는 거죠?b럴럴필 요요? ???

이건 속임수 질문입니다. b는 입력 입니다.sc_and방법은 항상 평가됩니다. 말하면 꿔꿔 in in in in in in insc_and(a(), b())를 호출합니다.a()를 호출합니다.b()되지 않습니다), 그에 콜(순서는 보증되지 않습니다), 콜(순서는 보증되지 않습니다)sc_and a(), b() to to에 것a?b:03진 연산자 자체와는 아무런 관련이 없습니다. 완전히 단락될 수 있습니다.

갱신하다

내가 왜 이것을 '꼼수 질문'이라고 불렀는지에 대해:이는 '단락'을 고려해야 하는 명확한 컨텍스트가 없기 때문입니다(적어도 OP에 의해 재현된 것처럼).함수 정의만 주어졌을 때, 많은 사람들은 질문의 맥락함수본문에 대해 묻고 있다고 가정한다; 그들은 종종 함수 자체를 표현으로 간주하지 않는다.이것은 질문의 '꼼수'입니다.일반 프로그래밍에서는 특히 규칙에 대한 예외가 많은 C-likes와 같은 언어에서는 그렇게 할 수 없습니다.예를 들어 다음과 같이 질문한 경우:

다음 코드를 고려합니다.메인에서 호출되었을 때 단락 동작을 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자신의 도메인 고유의 언어로 오퍼레이터로서 콜이 통상의 동작과 같이 단락 동작을 나타내고 있는지를 평가합니다.3진 연산자에 초점을 맞추면 안 되고 대신 C/C++의 함수 호출 메커니즘에 초점을 맞춰야 하기 때문에 저는 이것이 전혀 트릭 질문이라고 생각하지 않습니다.sc_and서킷을 실행하는 , 숏 서킷을 , 숏 서킷을 사용합니다.#define( 이이 ( ( ( ( )

3차 연산자 자신이 단락을 하는 것을 단락이라고 부르느냐(또는 '조건부 평가'와 같은 다른 것)는 단락의 정의에 따라 다르며, 그에 대한 다양한 의견을 읽을 수 있습니다.제 의견으로는 그렇습니다만, 실제 질문이나 제가 왜 그것을 '꼼수'라고 불렀는지와는 크게 관련이 없습니다.

스테이트먼트가 언제

bool x = a && b++;  // a and b are of int type

"discute",b++가 피연산자일 .a에 대한 평가입니다.false(일부러), ,, 작에 대한 b발생하지 않습니다.

이제 기능을 살펴보겠습니다.

bool and_fun(int a, int b)
{
     return a && b; 
}

그리고 이것을 부른다.

bool x = and_fun(a, b++);

「」의 유무에 ,atrue ★★★★★★★★★★★★★★★★★」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되지 않기 수 있습니다.

(초안) ANSI C 표준에서 발췌한 내용은 다음과 같다.

2.1.2.3 프로그램 실행

...

추상기계에서 모든 표현은 의미론에 의해 지정된 대로 평가된다.실제 구현에서는 그 값이 사용되지 않고 필요한 부작용이 발생하지 않는다고 추론할 수 있는 경우(함수를 호출하거나 휘발성 객체에 액세스하여 발생하는 부작용 포함)에는 표현의 일부를 평가할 필요가 없습니다.

그리고.

3.3.2.2 함수 호출

....

의미론

...

함수에 대한 호출을 준비할 때 인수가 평가되고 각 파라미터에 대응하는 인수 값이 할당됩니다.

각 인수는 식으로서 평가되지만 인수 목록 전체는 식이 아니기 때문에 SCE 이외의 동작은 필수입니다.

C규격의 심층수 표면에 있는 스플래셔로서 다음 두 가지 측면에 대해 적절한 정보를 얻을 수 있으면 좋겠습니다.

  • 하면 됩니까?1 / 0의되 않않 ?? ???? ?? ??
  • 인수 리스트는 식입니까?(아닌 것 같아)

추신.

로 하여 C++를 정의합니다.sc_andinlineSCE는 취득되지 않습니다.@alk와 같이 C 매크로로 정의하면 확실히 그렇게 됩니다.

3차 연산 단락을 명확하게 표시하려면 정수 대신 함수 포인터를 사용하도록 코드를 약간 변경해 보십시오.

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:

따라서 다른 사람들이 올바르게 지적했듯이, 질문 요령은 단락되지 않는 통화 시 매개 변수 평가(값별 호출) 대신 단락을 수행하는 3원 연산자 동작('조건부 평가'라고 함)에 초점을 맞추는 것입니다.

C ternary 연산자는 하나의 식 a(조건)만을 평가하여 값이 반환될 가능성이 있는 경우 식 b 및 c에 의해 주어진 값을 결정하기 위해 단락할 수 없습니다.

다음 코드:

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 식은 & 또는 | 등의 다른 연산자에 의해 형성될 수 있습니다.이 연산자는 값을 반환하기 전에2개의 식을 평가할 수 있기 때문입니다만, 이것은 단락을 실행하는 3진 연산자로 간주되지 않고, 통상의 if 스테이트먼트와 같이 조건내에서 사용되는 연산자로 간주됩니다.

업데이트:

삼원 연산자가 단락 연산자라는 것에 대한 논란이 있다.이 인수는 오퍼랜드 전체를 평가하지 않는 오퍼레이터는 아래 코멘트의 @aruisdante에 따라 단락을 실행한다고 말합니다.만약 이 정의가 주어진다면, 삼원 연산자는 단락이 될 것이고, 이것이 원래의 정의인 경우, 나는 동의한다.문제는 원래 '단락'이라는 용어는 이 동작을 허용하는 특정 종류의 연산자를 의미하며, 논리 연산자/부울 연산자이며, 그 이유는 이것들뿐이라는 것입니다.

그 기사 Short-circuit 평가에 이어이 단락 평가만 논리 사업자 어디에서 첫번째 피연산자 두번째를 부적절하게 만들 것이다 아는 것 방식으로 이 언어로 구현될 및,&연산자는 첫번째 피연산자는 허위, 그리고 || 연산자는 첫번째 피연산자 이것이 사실이라면 이, 이건 언급된다. C11 spec는 6.5.13 논리 AND 연산자 및 6.5.14 논리 OR 연산자에도 기재되어 있습니다.

즉, 단락 동작을 식별하기 위해서는 첫 번째 피연산자가 두 번째 피연산자와 무관하지 않을 경우 부울 연산자와 마찬가지로 모든 피연산자를 평가해야 하는 연산자에서 식별해야 합니다.이는 논리 연산자에서 단락이 발생하므로 MathWorks의 "논리 단락" 섹션에 있는 단락에 대한 다른 정의와 일치합니다.

지금까지 3차 연산자를 설명하려고 했습니다만, 3차 연산자는 피연산자 중 2개만 평가하면 첫 번째 연산자를 평가한 후 두 번째 연산자를 평가합니다.첫 번째 연산자의 값은 첫 번째 연산자의 값에 따라 달라집니다.항상 이렇게 합니다.어떤 상황에서든 3가지 모두를 평가해서는 안 되기 때문에 어떤 경우에도 "단락"은 발생하지 않습니다.

항상 그렇듯이 뭔가 옳지 않다고 생각되면, SO의 경험을 악화시킬 뿐 아니라 반대 의견을 써주세요.그리고 저는 우리가 단지 낮은 투표로 대답할 수 없는 훨씬 더 나은 커뮤니티가 될 수 있다고 믿습니다.

언급URL : https://stackoverflow.com/questions/26343355/why-is-this-version-of-logical-and-in-c-not-showing-short-circuit-behavior