C 및 C ++의 시퀀스 포인트로 인해 어떤 문제가 발생 했습니까?

StackOverflow https://stackoverflow.com/questions/859433

  •  21-08-2019
  •  | 
  •  

문제

아래는 시퀀스 지점 규칙으로 인해 정의되지 않은 동작을 초래하는 두 가지 일반적인 문제입니다.

a[i] = i++; //has a read and write between sequence points
i = i++;   //2 writes between sequence points

시퀀스 포인트와 관련하여 다른 것들은 무엇입니까?

컴파일러가 우리에게 경고 할 수 없을 때 이러한 문제를 찾기가 정말 어렵습니다.

도움이 되었습니까?

해결책 3

다음은 Bjarne Stroustup의 C ++를 사용한 프로그래밍 원칙 및 관행의 간단한 규칙입니다.

"표현식에서 변수의 값을 변경하면 같은 표현식으로 두 번 읽거나 쓰지 마십시오."

a[i] = i++; //i's value is changed once but read twice
i = i++;   //i's value is changed once but written twice

다른 팁

Dario의 예의 변형은 다음과 같습니다.

void Foo(shared_ptr<Bar> a, shared_ptr<Bar> b){ ... }

int main() {
  Foo(shared_ptr<Bar>(new Bar), shared_ptr<Bar>(new Bar));
}

메모리 누출 일 수 있습니다. 두 매개 변수의 평가 사이에는 시퀀스 지점이 없으므로 두 번째 인수는 첫 번째 인수보다 먼저 평가 될 수있을뿐만 아니라 두 막대 객체 모두가 생성 될 수 있습니다. shared_ptr'에스

즉, 평가받는 대신

Bar* b0 = new Bar();
arg0 = shared_ptr<Bar>(b0);
Bar* b1 = new Bar();
arg1 = shared_ptr<Bar>(b1);
Foo(arg0, arg1);

(만약 그렇다면 안전 할 것입니다 b0 성공적으로 할당되면 즉시 래핑됩니다. shared_ptr), 그것은 다음과 같이 평가 될 수 있습니다.

Bar* b0 = new Bar();
Bar* b1 = new Bar();
arg0 = shared_ptr<Bar>(b0);
arg1 = shared_ptr<Bar>(b1);
Foo(arg0, arg1);

즉, IF를 의미합니다 b0 성공적으로 할당됩니다 b1 그러면 예외가 발생합니다 b0 절대 삭제되지 않습니다.

매개 변수 목록에서 실행 순서 또는 예를 들어 추가에 관한 모호한 사례가 있습니다.

#include <iostream>

using namespace std;

int a() {
    cout << "Eval a" << endl;
    return 1;
}

int b() { 
    cout << "Eval b" << endl;
    return 2;
}

int plus(int x, int y) {
    return x + y;
}

int main() {

    int x = a() + b();
    int res = plus(a(), b());

    return 0;
}

A () 또는 B ()가 먼저 실행됩니까? ;-)

Dario와 유사한 예를 들었습니다.

printf("%s %s\n", inet_ntoa(&addr1), inet_ntoa(&addr2));

이것은 인쇄 할뿐만 아니라 "addr1 addr1" 또는 "addr2 addr2" (왜냐하면 inet_ntoa 추가 호출에 의해 덮어 쓰인 정적 버퍼에 대한 포인터를 반환하지만, 또한 이들 중 어느 것이 그렇지 않을지 정의되지 않습니다 (C는 인수 목록에 평가 순서를 지정하지 않기 때문에).

다음은 대부분의 C 컴파일러에서 작동하지만 시퀀스 지점으로 인해 모호한 두 가지 좋은 표현입니다.

x ^= y ^= x ^= y; // in-place swap of two variables

그리고 또한

int i=0;
printf("%d %d %d", ++i, ++i, ++i);  // usually prints out 3 2 1... but not for all compilers!

내가 최근에 본 것은 클래스 서식 시간을 절약하려는 프로그래머가 완전히 잘못된 머리를 절약하기 때문입니다.


class A
{
public:

    ...

    const char* Format( const string& f ) const
    {
        fmt = Print( f, value );
        return fmt.c_str();
    }

    operator const char* () const { return fmt.c_str(); }

private:

    struct timeval value;
    mutable string fmt;
};

A a( ... );
printf( "%s %s\n", a.Format( x ), a.Format( y );

마지막 줄은 항상 두 형식 모두에 대해 동일한 값을 인쇄합니다 (또는 내부 문자열이 반환 된 메모리를 해제하기 때문에 프로그램이 충돌합니다).

다른 하나는 내가 오래 전에했던 인터뷰에서 나온 것입니다.


void func( int x, int y, int z )
{
    printf( "%d %d %d\n", x, y, z );
}

...
int i = 0;
func( i, ++i, i++ ); /* don't do this in real software :) */

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top