C 및 C ++의 시퀀스 포인트로 인해 어떤 문제가 발생 했습니까?
-
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 :) */