'Basic Concept'에 해당되는 글 2건

  1. 2012.02.10 C++ Basic Concept, Storage Duration
  2. 2012.02.07 C++ Basic Concept, One definition rule (ODR) 2

C++ Basic Concept, Storage Duration

Short Articles 2012. 2. 10. 12:21
Sotrage duration 이란 object 에 대해서 object 를 포함하고 있는 storage 의 최소 유효 생명 주기를
정의하는 속성 입니다. Storage duration 는 다음과 같은 것들이 있습니다.
  • Static storage duration
  • Thread storage duration
  • Automatic storage duration
  • Dynamic storage duration 

작성중...
 
 
:

C++ Basic Concept, One definition rule (ODR)

Short Articles 2012. 2. 7. 14:57
(이 글은 C++ Templates the Complete Guide 부록의 내용을 바탕으로 작성되었습니다.)

C++ , ODR 에서 어떤 변수, 함수, 클래스 형, 열거 형 또는 템플릿도 번역 단위 내에서
딱 한 번만 정의 되어야 한다고 규정하고 있습니다.

+번역단위
번역 단위는 #define 매크로 치환등의 전처리 적용 이후 컴파일러에게 전달되는 코드의 덩어리를 지칭합니다.
컴파일러가 하나의 object 를 생성해내는데 참조하게 되는 코드 범위를 가리킨다고 볼 수 있고요.
따라서 파일 단위와는 차이가 있습니다. 

예를 하나 들어 보겠습니다.

a.h
a.cpp
main.cpp
이렇게 3개의 파일이 있다고 했을 때, 컴파일러는 a.cpp , main.cpp 두 소스 파일에 대해서 각각
a.obj , main.obj (g++ 이라면 a.o , main.o) 라는 오브젝트 파일을 생성합니다.
이 때 컴파일러에 전달되는 것은 '#include '로 포함된 파일의 내용이 추가된 코드 덩어리 입니다.

컴파일러는 이렇게 각 각의 코드 덩어리를 해석하기 때문에
foo() 함수의 정의는 a.obj 에 기록 되지만 main.obj 에는 foo() 함수의 구현을 모릅니다.
main.obj 는 단지 foo() 함수의 symbol 정보만을 들고 있습니다.
이것은 linking 과정에서 linker 에 의해 해석되어 구현 코드와 연결되게 됩니다.

ms윈도우에서 vs 기반으로 작업을 하시는 분들 중에 이런식의 컴파일/링킹 과정을 
분리해서 생각 하는 것에 생소한 분들이 좀 있는 것 같습니다. 
a.cpp 파일이 없더라도 컴파일 과정은 문제 없이 수행됩니다.

컴파일러가 cl.exe 라면 /c 옵션을 주어 컴파일 과정만을 수행할 수 있습니다.




아무튼 위에서의 foo() 함수 같은 경우에 external linkage 를 갖는다고 합니다. 반대로 같은 번역 단위에
존재할 경우에는 internal linkage 를 갖는다고 하죠.

다시 ODR 에 대한 이야기로 돌아가서..

+ ODR 에 따라 프로그램에서 단 한번만 정의 되어야하는 것에는 다음과 같은 것들이 있습니다.
    • 인라인이 아닌 함수/인라인이 아닌 멤버 함수
    • external linkage 를 갖는 정적 데이터 멤버
    • 인라인이 아닌 (함수 템플릿/멤버 함수 템플릿/클래스 템플릿 멤버) 가 export 와 함께 선언된 경우
    • 클래스 템플릿의 정적 데이터 멤버가 export 로 선언된 경우 
이 것들은 external linkage 를 갖는 사항들로 internal linkage 를 갖는 것들에 대해서는 적용되지 않습니다.
(번역단위 내에 선언된 static 변수,  anonymous namespace 등은 internal linkage 를 갖습니다.)

프로그램 내에서 어떤 실체에 대해 사용(명시적이든 묵시적이든 참조를 하는)이 있을 경우,
이 실체는 프로그램 내에 하나만 존재 해야 합니다. 
이 규칙에 대해 (sizeof , typeid) 사용이 좀 예외적일 수가 있는데
이 둘의 연산자의 일부로써 실체에 대한 참조가 일어날 경우 기본적으로는 실체가 사용되었다고 보지 않지만
typeid 연산자의 인자가 다형적 객체(상속, 가상 함수를 포함)를 가리키는 경우에는 사용되었다고 판단합니다.


+ 번역 단위 내에서 실체는 한 번 이상 정의 될 수 없습니다.
구조체/공용체를 포함한 클래스 타입은 번역 단위 내에서 다음과 같은 사용 사항들에 대해
정의돼 있어야 합니다.
  • 객체의 생성(포함관계 등으로 인한 간접 생성을 포함)
  • 데이터 멤버의 선언 
  • 객체에 대한 sizeof / typeid 연산자
  • 멤버에 대한 (명시적/암시적) 접근
  • 임의의 어떤 변환을 사용한 표현식 - 클래스 타입 상호간 변환
  • 암시적 형변환, static_cast, dynamic_cast 를 사용한 표현식 - (void*를 제외한)클래스 포인터(또는 참조) 상호간 변환
  • 값의 할당
  • (인자나 리턴 타입을 포함)함수 정의 또는 호출, 그러나 선언만의 경우 정의될 필요 없음.
 
이 규칙은 클래스 템플릿을 통해 생성되는 클래스 타입에 대해서도 적용됩니다.
즉, 클래스 타입을 인스턴싱 시키는 클래스 템플릿은 위와 같은 상황에 대해 정의되어 있어야 합니다.

인라인 함수들의 경우에는 인라인 함수가 사용되는 각각의 번역 단위에 정의가 있어야 합니다.
인라인은 코드 치환이므로 심볼만을 인식하고 있는 경우 코드 정의를 치환할 수 없습니다.
 
+ 교차 번역 단위에서의 동등성 제약
이 부분은 설명 생략하겠습니다.
참고적으로, MS 의 c++ 컴파일러인 cl.exe 는 다중 정의 자체를 허용 하지 않습니다.
관련해서 검색해보시고 테스트 해보실 분은 g++ 을 이용하여 테스트 해보시기 바랍니다.


 

'Short Articles' 카테고리의 다른 글

C++ Template, Expression Templates #2  (0) 2012.02.17
C++ Basic Concept, Storage Duration  (0) 2012.02.10
C++ Template, Expression Templates #1  (3) 2012.02.08
C++11, Lambda Expressions #2  (0) 2012.02.01
C++11, Lambda Expressions #1  (2) 2012.01.30
: