2012-12-17 3 views
1

G ++에 의해 무시되고 :통근 const를 연동 규격은 겉으로 나는이 평행 C++ 컴파일러와 C 코드베이스를 구축하는 상황이

lib.h

extern int const values[2] = {1, 2}; 

lib.c

#include "lib.h" 

main.c를

#include <iostream> 

extern int const values[2]; 

int main() { 
    std::cout << values[0] << ":" << values[1] << std::endl; 
} 

C++03 Standard Annex C Compatibility C.1.2 Clause 3에 지적 된 사항 때문에 extern을 추가해야했습니다.

$ objdump -t lib.o | grep values 
0000000000000000 l  O .rodata 0000000000000008 _ZL6values 

$ objdump -t main.o | grep values 
0000000000000000   *UND* 0000000000000000 values 

을 ... 그리고 그것은 같다 : extern 전에

이 덧붙여이 values은 objdump를에 표시되는 방법에하게 차이가 이런 식이다 (. -fpermissive로 컴파일하면 양탄자에 따라 본을 쓸어)

$ objdump -t lib.o | grep values 
0000000000000000 g  O .rodata 0000000000000008 values 

$ objdump -t main.o | grep values 
0000000000000000   *UND* 0000000000000000 values 

, 우리는 "L"는 "G"로 전환을 그래서 이름 맹 글링이 떨어졌다보고, 링커에 대한 0,123,402,576 불평하지 않습니다 :이은을 첨가 한 후이 정의되지 않았습니다.


지금 같은 방식으로 수정이 개 매우 유사한 파일과 같은 상황을 상상 :

TMP-exttypes.h

extern const REBYTE Reb_To_RXT[REB_MAX] = { /* bunch of stuff */ }; 

A-lib.c

extern const REBYTE Reb_To_RXT[REB_MAX]; 

다음은 프로젝트에서 Reb_To_RXT 정의는 두 개만 만들어졌으며 깨끗하게 만들었습니다. 그러나 연결 아니에요 나는 그것을 언급하는 유일한 두 개의 파일을 objdump를 할 때 내가 얻을 :

$ objdump -t a-lib.o | grep Reb_To_RXT 
00000000   *UND* 00000000 Reb_To_RXT 

$ objdump -t f-extension.o | grep Reb_To_RXT 
00000080 l  O .rodata 00000038 _ZL10Reb_To_RXT 

그것은 L 말한다, 그리고 이름 엉망입니다. 어느 것이 훨씬 간단한 예제를 행복하게 만들지 못했습니다. 그러나 나는 이것이 외모가 생길 때 어떻게 외계인이 일어날 수 있는지 궁금합니다. 나는 이것이 총기류라고 믿는 것이 옳은가? 그리고 일반적으로 extern으로 선언 된 것만이 국부적 인 연계성을 가져서는 안되는 것이 일어날 것이라고 생각하지는 않는가?

답변

3

당신이 무엇을 의미하는지 이해할 수 없습니다. 으로 문의하십시오.

하지만 & hellip; 해당 헤더가 하나 개 이상의 번역 단위에 포함되어있는 경우

헤더 파일에

extern int const values[2] = {1, 2}; 

을 가지고, 당신은 UB 있습니다. 가장 가능성이 있지만 꼭 그렇지는 않은 연결 오류가 발생합니다.

한 용액 :

extern int const values[2]; 

같이, 헤더의 배열을 선언하지만 실행 파일 (이니셜로)를 정의한다.

다른 해결책은 템플릿 트릭이나 인라인 함수 트릭을 사용하여 헤더 파일에 배열을 정의하는 것입니다.

인라인 함수 트릭 :

typedef int const Values[2]; 

inline Values& valuesRef() 
{ 
    static Values theValues = {1, 2}; 
    return theValues; 
} 

static Values& values = valuesRef(); 
+0

프로토 타입 그리고 내가 그것을했을 거라고 어떻게 물론 하나의 정의를 선호하는 것입니다. 하지만 내가 적응하고있는 코드는 다른 사람의 C 다. 그리고 그것을 바꿀 수있는 힘든 싸움이 될 수도있다. 하지만 C조차도 UB라는 표제가 있다면 더 많은 탄약이있을 수 있습니다 ...? :/ – HostileFork

+0

@HostileFork C++ 11에서는 배열을'constexpr'로 선언하고 초기화 할 수 있습니다. 그러나 글로벌 객체를 두 번 정의하면 ODR을 위반하게되며 즉시 UB가됩니다. – Potatoswatter

+1

@HostileFork : C99, §6.9/5의 마지막 초안 (N869) : "외부 정의는 함수 또는 객체의 정의이기도 한 외부 선언입니다. 외부 연결로 선언 된 식별자가 사용 된 경우 표현식 (sizeof 연산자의 오퍼랜드의 일부로 제외)에서 전체 프로그램 어딘가에 식별자에 대한 하나의 외부 정의가 있어야하며, 그렇지 않은 경우에는 하나만 존재해야합니다. " 나중의 표준 인 C11이 있지만 근본적인 것이 바뀌 었다고 상상할 수는 없습니다. MSVC는 C89 (C99가 아니라 C89가 아닙니다)를 구현합니다 ... –

1

예, 맞습니다.

당신이 편집 한 파일은 자동 생성되었으며 실제로는 생각이 풀린 과정을 중간에 기록한 깨끗한 제작자에 의해 파괴되었습니다. 그 특정 헤더에서 볼 수있는 "tmp"는 "임시, 편집하지 말 것"을 암시하고, 파일을 편집기에서 다시로드하지 않으면 혼란 스러울 수 있습니다.

(어쨌든 기관 지식을위한 생각의 기차를 끝내십시오.: -P)