2013-07-17 2 views
0
#include <stdio.h> 

namespace myname{ 
    double var = 42; 
} 

extern "C" double _ZN6myname3varE = 10.0; 

int main(){ 
    printf("%d\n", _ZN6myname3varE); 
    return 0; 
} 

gcc 컴파일 결과는 다음과 같습니다gcc 내부 기호 장식에 어떤 문제가 있습니까?

[email protected]:~/workspace/vi_edit$ g++ testSymble.cpp -o testSymble 
testSymble.cpp:7:19: warning: ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default] 
testSymble.cpp: In function ‘int main()’: 
testSymble.cpp:10:32: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat] 
/tmp/cczIjRfH.s: Assembler messages: 
/tmp/cczIjRfH.s:14: Error: symbol `_ZN6myname3varE' is already defined 

_ZN6myname3varE 재정의?
경고 ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]은 무엇을 의미합니까? 명시 적으로이 조항에 의해 허용 된 다른 것보다


프로그램이 선언하거나이 예약되어 문맥에 이름을 정의하는 경우

는 동작은 정의되지 않습니다.

17.4.3.1.2 글로벌 이름
이중 밑줄을 포함 (_ _) 또는 대문자 편지 (2.11) 다음에 밑줄로 시작 각각의 이름은 여러 용도로 구현에 예약되어 있습니다.

+6

'_Zxyz ...'와 같이 대문자가 뒤에 오는 기호 이름은 구현 (즉, 컴파일러 도구 체인)에서 사용하도록 예약되어 있습니다. 그러한 심볼을 선언하거나 정의하는 것만으로 * 정의되지 않은 동작 * (C99 §7.1.3/1-2, C++ 03 §17.4.3.1/1, §17.4.3.1.2)이됩니다. –

답변

0

첫 번째 경고 메시지는 변수 선언에 extern을 포함하면 이니셜 라이저를 포함 할 수 없다는 것을 의미합니다.따라서,이 라인 모두는 경고를 생성합니다

extern "C" int i = 9; 
extern  int j = 10; 

을 다음 중 하나를 수행 할 수 있습니다 쓰기 :

int i = 9; 
int j = 10; 

나 :

extern "C" int i; 
extern  int j; 

또는, 당신이 할 수있는 (A comment 아웃 Adam Rosenfield 점 등) 회선에 중괄호를 포함하여 초기화 프로그램을 허용하십시오.

extern "C" { int i = 9; } 

이 코드에 적용, 당신은 extern "C" 줄에 초기화 = 42을 넣지하거나 작성할 필요가 :

extern "C" { double _ZN6myname3varE = 10.0; } 
격리에서

, 마지막 문제를 무시하고, 그해야 '작업'.

두 번째 경고는 namespace myname { double var = 42; }double이므로 %d 변환 지정이 잘못되었음을 의미합니다. %f 또는 %e 또는 %g이거나이 주제의 변형이어야합니다.

printf("%f\n", myname::var); 

세 번째 오류 메시지는 어셈블러에서 온 것입니다. 첫 번째 메시지는 경고 일 뿐이므로 실제 두 개의 다른 정의가 있습니다. 두 개의 다른 정의가 있는데, 두 개의 다른 초기화 프로그램을 사용하여 맹 글링하면 _ZN6myname3varE으로 변환됩니다. 당신은 하나의 정의 - 하나의 정의 규칙 만 허용됩니다.

그러나 밑줄 문자와 그 뒤에 대문자로 시작하는 이름은 구현을 위해 예약되어 있으므로 _ZN6myname3varE이라는 이름을 직접 사용하면 정의되지 않은 동작이 호출됩니다. 정의되지 않은 동작을 사용하지 마십시오. 그것을 피하십시오.

3

_ZN6myname3varE은 왜 다시 정의됩니까?

는 C++ myname::var 변수 GCC에 의해 _ZN6myname3varEname-mangled이다. _ZN6myname3varE이라는 C (즉, 맹 글링되지 않은) 변수도 정의했습니다. 따라서 동일한 기호에 대해 여러 정의가 있습니다.


경고 [...] 무엇을 의미합니까?

표준 사용법은 다음과 같습니다

foo.h

extern "C" int myvariable; 

foo.c를/CC

#include "foo.h" 

int myvariable = 42; 

잘 모르겠어요 C++ 표준 허용 여부 extern "C" 변수 초기화 (예 : 당신은하고 있어요). 그러나 컴파일러는 확실히 당신이하고있는 일이 아마 이치에 맞지 않는다고 경고합니다.

+0

경고 부분은 어떻게됩니까? – Zachary

+1

@Zack 그것은 'extern' 변수를 초기화하는 것이 적절하지 않기 때문입니다. –

+0

extern 변수를 초기화 할 때 새 변수를 정의하는 것과 같습니다. 내가 할 수 있을까? – Zachary