내보낸 일부 const 변수를 참조하는 일부 const 변수가 값 0을 얻는 이유는 무엇입니까?

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

문제

다음을 고려하세요.다음과 같이 두 개의 내보낸 상수가 있습니다.

// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;

그리고

// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;

이제 이러한 상수는 두 개의 정적(로컬로 표시되는) 상수를 정의하기 위해 다른 곳에서 참조됩니다.

// someotherfile.cpp
#include "somefile.h"
static const double cAnotherDouble = 1.1*cMyConstDouble;
static const double cAnotherDouble2 = 1.1*cMyConstDouble2;
printf("cAnotherDouble = %g, cAnotherDouble2 = %g\n",
       cAnotherDouble, cAnotherDouble2);

결과는 다음과 같습니다.

cAnotherDouble = 3.454, cAnotherDouble2 = 0

왜 두 번째 double은 0입니까?저는 .NET 2003 C++ 컴파일러(13.10.3077)를 사용하고 있습니다.

도움이 되었습니까?

해결책

CMYCONSTDOUBLE은 외부로 선언되므로 컴파일러는 그 값을 가정 할 수 없으며 CMYCONSTDOUBLE2의 컴파일 시간 초기화를 생성하지 않습니다. cmyconstdouble2가 컴파일 시간 초기화되지 않으므로 CanotherDouble2에 대한 초기화 순서는 무작위 (정의되지 않은)입니다. 보다 정적 초기화 치실 자세한 내용은.

다른 팁

나는 여기에서 내 발가락을 extern 문제에 담그지 않을 것이지만, 왜 단순히 구성원을 적절한 헤더 파일에 배치하지 않고 외부를 사용하여 "내보내기"를 잊어 버리나요? 이것이 C ++에서 Ocsts를 사용하는 방법과 내부 연계가있는 이유입니다.

다시 말해:

// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;

그리고 필요한 파일을 필요로하십시오.

한 소스 파일의 하나의 정적 변수가 다른 CPP 파일의 다른 정적 변수에 의존하기 때문에 이것은 위험합니다. 확인하다 정적 초기화 치실 자세한 내용은.

초기화를 변경하면 cMyConstDouble2 여기에:

const double cMyConstDouble2 = 2.5*3.14;

그러면 프로그램이 올바르게 작동해야 합니다.그 이유는 변수가

  • POD 유형 있음
  • 상수 표현식으로 초기화됩니다. (1)

정적 초기화 시간에 초기화됩니다.이러한 초기화에는 다음이 포함됩니다.

  • 제로 초기화 모두 정적 저장 기간을 갖는 객체
  • 상수 표현식으로 초기화된 POD 초기화

표시된 변수 중 cMyConstDouble 정적 초기화 시점에 완전히 초기화된다는 두 가지 조건을 모두 만족합니다.하지만, cMyConstDouble2 초기화가 상수 표현식의 요구 사항을 충족하지 않기 때문에 그렇지 않습니다.특히 정수형이 아닌 변수(여기서는 부동소수점형)가 포함되어 있습니다.그러나 부동소수점 리터럴 ~이다 산술 상수 표현식에 허용됩니다.그렇기 때문에 2.5*3.14 산술 상수 표현입니다.이것이 바로 초기화 프로그램을 변경하면 정적으로 초기화되어야 하는 이유입니다.


무슨 일이 일어날 것인가? cMyConstDouble2 상수가 아닌 표현을 유지한다면?대답은 '당신은 모른다'입니다.표준에서는 해당 변수를 정적으로 초기화하는 것을 허용하지만 그렇게 할 것을 요구하지는 않습니다.귀하의 경우 동적으로 초기화되었으므로 정적 초기화 시간 직후의 값은 여전히 ​​0입니다.방법에 대한 느낌을 얻으려면 복잡한 즉, 다음은 예입니다.

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
                // may be statically initialized to 0.0 or
                // dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0

동적 초기화가 다른 정적 저장 변수를 변경하지 않는 경우(다음에서 충족됨) 당신의 코드) 그리고 정적 초기화가 정적 초기화가 필요하지 않은 모든 개체가 동적으로 초기화될 때 동적 초기화에 의해 생성되는 것과 동일한 값을 생성하는 경우(또한 당신의 코드) - 그러면 변수가 정적으로 초기화될 수 있습니다.이 두 조건은 두 변수에 대한 위의 코드에서도 충족됩니다. d2 그리고 d1:

분석 d2

  • = d1 다른 정적 저장 변수는 변경되지 않습니다.
  • 둘 다일 때 d2 그리고 d1 동적으로 초기화된 다음 d2 다음과 같이 초기화됩니다. 0.0, 왜냐하면 d2 이전에 정의되었습니다 d1, 및 동적 초기화 d2 의 가치를 잡을 것이다 d1 정적 초기화 직후 상태 기준(제로 초기화만 d1 일어났습니다).

분석 d1

  • = fd() 다른 정적 저장 변수는 변경되지 않습니다.
  • 둘 다일 때 d2 그리고 d1 동적으로 초기화된 다음 = fd() 초기화됩니다 d1 에게 1.0.

따라서 컴파일러는 초기화할 수 있습니다. d1 정적으로 1.0, 선택적 정적 초기화에 대한 두 조건이 모두 충족되기 때문입니다.

  • 만약에 컴파일러는 초기화를 결정합니다 d1 그리고 d2 동적으로 d2 로 초기화됩니다 0.0, 왜냐하면 그것은 d1 제로 초기화 직후였습니다.

  • 하지만, 만약에 컴파일러는 초기화를 결정합니다 d1 정적으로 그리고 d2 동적으로 d2 로 초기화됩니다 1.0, 동적 초기화 이후 d2 완전히 초기화된 값을 가져옵니다. d1 정적 초기화 직후였습니다.

그 가치가 무엇인지 잘 모르겠습니다. d2 언제인가? d1 그리고 d2 그러나 정적으로 초기화됩니다.즉, 여부 d2 잡아야 할 것 같다. 0.0 아니면 그 1.0, 정적 초기화에는 정의된 순서가 없기 때문입니다.


(1) 상수 표현식에는 정적 저장 기간이 있는 객체의 초기화 순서를 고려할 때 산술 상수 표현식(적분 상수 표현식뿐만 아니라)도 포함됩니다.

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