source

f가 x를 수정하면 x*f(x)의 값이 지정되지 않습니까?

manysource 2023. 10. 7. 12:00

f가 x를 수정하면 x*f(x)의 값이 지정되지 않습니까?

질문을 의 x*f(x)됩니다인 경우 됩니다.f합니다.x요?f(x)*x.

다음 코드를 고려합니다.

#include <iostream>

int fx(int &x) {
  x = x + 1;
  return x;
}

int f1(int &x) {
  return fx(x)*x; // Line A
}

int f2(int &x) {
  return x*fx(x); // Line B
}

int main(void) {
  int a = 6, b = 6;
  std::cout << f1(a) << " " << f2(b) << std::endl;
}

합니다.49 42on g++ 4.8.4 (Ubuntu 14.04).

이것이 보장된 행동인지, 불특정 행동인지 궁금합니다.

fx됩니다와 두 를 받습니다.x=6두 번 모두 7번을 반환합니다. A가 이 있습니다입니다 A가 7*7인의 값을 합니다). 하면)xfx을 계산하는 B는 을 계산하고을 사용),인 B는는 6*7을합니다합니다합니다).x전에fx반환).

이것이 보장된 행동입니까?예인 경우 표준의 어떤 부분에서 이를 명시합니까?

기능을 : int *xint &x면,를 얻습니다.C동일한 문제를 가진 코드.C에 대한 답이 다른가요?

를 가 더 .x*f(x)마치:

operator*(x, f(x));

곱셈이 어떻게 작용하는지에 대한 수학적 선입견이 없도록 해야 합니다.

@dan04가 유용하게 지적한 바와 같이, 표준은 다음과 같이 말합니다.

섹션 1.9.15: "주어진 경우를 제외하고, 개별 사업자의 피연산자 및 개별 표현식의 하위 표현에 대한 평가는 순차적이지 않습니다."

를 순서에 할 수 시퀀스 는 합니다입니다. 시퀀스 포인트는 다음과 같습니다.operator*operator*가 호출되며, 두 인수를 모두 평가해야 합니다.

예를 들어, 개념적으로, 적어도 하나의 논쟁이 7이 될 것이라고 확신할 수 있지만, 두 논쟁 모두가 7이 될 것이라고 확신할 수는 없습니다.이는 이 동작을 정의되지 않은 것으로 분류하기에 충분합니다. 그러나 @user2079303 답변은 기술적으로 그렇지 않은 이유를 잘 설명해 줍니다.

동작이 정의되지 않은 것인지 또는 불확실한 것인지에 관계없이, 잘 동작하는 프로그램에서는 이러한 표현을 사용할 수 없습니다.

인수의 평가 순서는 표준에 의해 지정되지 않으므로 표시되는 동작이 보장되지 않습니다.

sequence point를 말씀해주셨기 때문에 그 용어를 사용하는 c++03 표준을 고려해 보겠습니다.

ISO/IEC 14882:2003(E) §5/4:

개별 사업자의 피연산자 평가 및 개별 표현의 하위 표현 순서, 부작용이 발생하는 순서 등이 명시되지 않은 경우를 제외하고는...


이것이 정의되지 않은 행동인지 아니면 단지 순서가 지정되지 않은 것인지에 대해서도 논의가 있습니다.그 단락의 나머지 부분은 그것에 대해 약간의 빛(혹은 의심)을 보여줍니다.

ISO/IEC 14882:2003(E) §5/4:

... 이전 시퀀스 포인트와 다음 시퀀스 포인트 사이에서 스칼라 객체는 식의 평가에 의해 저장된 값이 최대 한 번 수정되어야 합니다.또한 이전 값은 저장할 값을 결정하기 위해서만 접근해야 합니다.본 항의 요건은 완전한 식의 하위 표현의 허용되는 각 순서에 대해 충족되어야 하며, 그렇지 않으면 동작이 정의되지 않습니다.

x입니다에서 된 것입니다.ff라고 합니다.다 되어 있지 않습니다.x수정된 값 또는 수정되지 않은 값을 읽습니다.그것은 당신에게 "정의되지 않은 행동"이라고 소리칠지도 모르지만, 당신의 말을 참으세요. 왜냐하면 표준은 또한 다음과 같이 명시되어 있기 때문입니다.

ISO/IEC 14882:2003(E) §1.9/17:

... 함수를 호출할 때(함수가 인라인이든 아니든), 함수 본문에서 모든 함수 인수를 평가한 후(있는 경우) 함수 본문에서 식을 실행하기 전에 수행되는 시퀀스 포인트가 있습니다.반환된 값을 복사한 후 함수 외부의 식을 실행하기 전에 시퀀스 포인트도 있습니다.

그래서 만약에f(x)를 먼저 평가한 다음 반환된 값을 복사한 후 시퀀스 포인트가 있습니다. UB에 다 UB의 . 왜냐하면 읽기 때문입니다.x다음 시퀀스 포인트와 이전 시퀀스 포인트 사이에 있지 않습니다.x이 있습니다다.

한다면x다,가 있습니다.f(x)역시 UB에 관한 규정은 적용되지 않습니다.nxoperand다.

요약하면 순서는 지정되지 않았지만 정의되지 않은 동작은 없습니다.버그지만 결과는 어느 정도 예측 가능합니다.문구가 바뀌어도 행동은 이후 기준에서도 마찬가지입니다.이미 다른 좋은 답변들에서 잘 다뤄졌기 때문에 저는 그것들에 대해 자세히 다루지 않겠습니다.


당신이 C의 비슷한 상황을 물었으니깐.

C89(초안) 3.3/3:

구문으로 표시되거나 나중에 달리 지정된 경우(함수 호출 연산자( ), &&, ||, ?: 및 쉼표 연산자의 경우)를 제외하고 하위 표현식의 평가 순서와 부작용이 발생하는 순서는 모두 지정되지 않습니다.

함수 호출 예외는 여기에 이미 언급되어 있습니다.다음은 시퀀스 포인트가 없는 경우 정의되지 않은 동작을 암시하는 문단입니다.

C89(초안) 3.3/2:

이전 시퀀스 포인트와 다음 시퀀스 포인트 사이에 객체는 식의 평가를 통해 최대 한 번까지 저장된 값을 수정해야 합니다.또한 이전 값은 저장할 값을 결정하기 위해서만 접근해야 합니다.26

그리고 정의된 시퀀스 포인트는 다음과 같습니다.

C89 (드래프트) A.2

다음은 2.1.2.3에 설명된 시퀀스 포인트입니다.

  • 인수를 평가한 후 함수에 대한 호출입니다(3.3.2.2).

  • ...

  • ... 답신문의 표현(3.6.6.4).

결론은 C++와 같습니다.

다른 답변에서 명확하게 다루지 않는 내용에 대한 간단한 메모:

x*f(x)됩니다인 경우 됩니다.f합니다.x요?f(x)*x.

막심의 대답처럼 생각해 보세요.

operator*(x, f(x));

이제 필요에 따라 통화 전에 두 인수를 평가하는 두 가지 방법만 있습니다.

auto lhs = x;        // or auto rhs = f(x);
auto rhs = f(x);     // or auto lhs = x;
    return lhs * rhs

그래서, 당신이 물었을 때.

이것이 보장된 행동인지, 불특정 행동인지 궁금합니다.

표준은 컴파일러가 선택해야 하는 두 가지 동작 에서 어떤 것을 선택해야 하는지는 명시하지 않지만, 그것이 유일하게 유효한 동작이라고 명시합니다.

그래서 보장된 것도 아니고 완전히 불특정한 것도 아닙니다.


아, 그리고:

시퀀스 포인트에 관한 질문을 많이 봤는데 평가 순서가...

시퀀스 포인트는 C 언어 표준에서 이를 처리하는 데 사용되지만 C++ 표준에서는 사용되지 않습니다.

에서 x * y, , x그리고.y순서가 없습니다.이것은 세 가지 가능한 순서 관계 중 하나이며, 다음은 다음과 같습니다.

  • A 가 매겨진 B:A모든 s이 면 효과를다하기 전에 .B합니다 g합니다 g
  • A그리고.B 불확정 순서: 다음 두 경우 중 하나가 참입니다.A sequenced-beforeB, 아니면B sequenced-beforeA. 그 두 경우 중 어느 것이 성립하는지는 구체적으로 밝혀지지 않았습니다.
  • A그리고.B 순서 없음:사이에 정의된 시퀀싱 관계가 없습니다.A그리고.B.

이들은 쌍대 관계라는 점에 유의해야 합니다.우리는 "라고 말할 수 없습니다.x순서가 없습니다." 는 두 가지 이지 않다고 입니다.우리는 두 작업이 서로에 대해 순차적이지 않다고 말할 수 있을 뿐입니다.

또한 중요한 것은 이 관계들이 과도기적이라는 것이고, 후자의 두 관계는 대칭적이라는 것입니다.


미지정이란 기술적 용어로 표준에서 가능한 결과의 수를 설정한 것을 의미합니다.이는 표준이 해당 행위를 전혀 다루지 않는다는 것을 의미하는 미정의 행위와는 다릅니다.자세한 내용은 여기를 참조하십시오.


하는 중 x * f(x) 와 .f(x) * x와 같이, ,x그리고.f(x)두 경우 모두 서로에 대해 순서가 정해지지 않았습니다.

이제 우리는 여러 사람들이 꼼짝 못하고 있는 것처럼 보이는 지경에 이르렀습니다.하는 중sf(x)에 관해서는 순서가 없습니다.그러나 기능 본체 내부의 어떤 문구도 뒤따르지 않습니다.f다에 가 정해지지 않았습니다.x 순서 할 수 실제로 함수 호출을 둘러싼 순서 관계가 있으며 이러한 관계는 무시할 수 없습니다.

다음은 C++14의 텍스트입니다.

함수를 호출할 때(함수가 인라인인지 여부에 관계없이), 호출된 함수를 지정하는 인수 식을 지정하거나 후 수정 식과 관련된 모든 값 계산 및 부작용은 호출된 함수 본문의 모든 식 또는 문을 실행하기 전에 순서화됩니다.[참고: 다양한 인수 표현과 관련된 값 계산 및 부작용은 순서화되지 않습니다.--end note ] 호출된 함수의 본문 실행 전후별도순서가 정해지지 않은 호출 함수의 모든 평가(다른 함수 호출 포함) 호출된 함수의 실행에 대해 불확정적으로 순서가 정해집니다.

각주 포함:

즉, 함수 실행은 서로 상호작용하지 않습니다.

굵게 표시된 텍스트는 두 식에 대해 다음과 같이 명확히 설명합니다.

  • A:x = x + 1;에서 안에f(x)
  • B: 첫 번째 평가xx * f(x)

그들의 관계는 다음과 같습니다. 불확정적으로 배열되어 있지 않습니다.

정의되지 않은 행동과 순서 결정에 관한 텍스트는 다음과 같습니다.

스칼라 객체에 대한 부작용이 동일한 스칼라 객체에 대한 다른 부작용 또는 동일한 스칼라 객체의 값을 사용한 값 계산에 상대적으로 시퀀싱되지 않은 경우(1.10), 동작은 정의되지 않습니다.

이 경우 관계는 순서가 정해지지 않은 것이 아니라 순서가 정해지지 않은 것입니다.따라서 정의되지 않은 행동은 없습니다.

그 결과는 대신 다음과 같은 경우에 따라 지정되지 않습니다.x다 에 시퀀싱됩니다.x = x + 1아니면 반대로.입니다라는 두 .42그리고.49.


가 그 에 을 품었을 .x인에f(x) 텍스트가 됩니다.됩니다.

함수를 호출할 때(함수가 인라인인지 여부에 관계없이), 호출된 함수를 지정하는 인수 식을 지정하거나 후 수정 식과 관련된 모든 값 계산 및 부작용은 호출된 함수 본문의 모든 식 또는 문을 실행하기 전에 순서화됩니다.

그 에 대한 .x전에 순서가 정해집니다. x = x + 1. 이는 위 굵은 인용문에서 "이전에 특정하게 배열된" 경우에 해당하는 평가의 예입니다.


각주: C++03에서는 동작이 완전히 같았지만 용어는 달랐습니다.C++03에서 우리는 모든 함수 호출의 진입과 종료 시 시퀀스 포인트가 존재한다고 말합니다. 따라서 다음에 기록합니다.x다의 됩니다.x적어도 하나의 시퀀스 포인트만큼 함수 밖에 있습니다.

다음을 구별해야 합니다.

a) 연산자 우선 순위 및 연관성 - 연산자가 하위 식의 값을 결합하는 순서를 제어합니다.

expression 순서.) 식에서 입니다.를 들어 f(x)/g(x)는 를 할 수 .g(x)처음에 그리고f(x)그 후.그럼에도 불구하고 결과 값은 당연히 각 하위 값을 올바른 순서로 나누어 계산해야 합니다.

c) 하위 표현식의 부작용 순서입니다.예를 들어, 컴파일러는 최적화를 위해 식의 끝이나 다른 적절한 장소에서만 영향을 받는 변수에 값을 쓰기로 결정할 수 있습니다.

매우 개략적인 근사치로서, 단일 식 내에서 평가 순서(연관성 등이 아님)가 다소 불특정하다고 할 수 있습니다.특정 평가 순서가 필요한 경우 식을 다음과 같은 일련의 문장으로 분해합니다.

int a = f(x); int b = g(x); return a/b;

대신에

return f(x)/g(x);

정확한 규칙은 http://en.cppreference.com/w/cpp/language/eval_order 을 참조하십시오.

거의 모든 C++ 연산자의 피연산자 평가 순서는 미정입니다.컴파일러는 어떤 순서로든 피연산자를 평가할 수 있고, 같은 식을 다시 평가할 때 다른 순서를 선택할 수 있습니다.

평가 순서가 항상 같지는 않기 때문에 예상치 못한 결과가 나올 수 있습니다.

평가순서

언급URL : https://stackoverflow.com/questions/32504524/is-value-of-xfx-unspecified-if-f-modifies-x