2009-11-06 3 views
3

의 이름을 해결 :C++ 컴파일러 - 클래스 멤버 컴파일러는이 코드를보고

SomeClass foo; 
int x = foo.bar; 

을 무엇입니까가 의 값을 검색에 대해 진행 과정? 나는. 그것은 클래스 정의를 나타내는 데이터 구조를 보았는가? 그렇다면이 데이터 구조는 컴파일 타임이나 런타임에 생성됩니까?

+2

내 자신을 포함하여 아래의 모든 대답은 "일반적인 컴파일러에서 정상적으로 수행되어야합니다"라고 가정해야합니다. C++의 구현과 관련이있는 거의 모든 것과 마찬가지로, "컴파일러 작성자는 전적으로 프로그램에 대한 올바른 대답이 나오는 한 언제든지 할 수 있습니다."라고 대답했습니다. 아래에서 설명하는 것은 악의적 인 최적화를 적용하기 전에 가장 분명하고 합리적인 방법입니다. –

답변

2

프로세스에 할당이 시작됩니다. 이 정의에 기초하여, SomeClass의 필드 및 SomeClass의 방법에 대한 코드의 위치의 종류를 포함하는 내부 구조를 구축한다. 당신이 을 쓸 때

컴파일러는 SomeClass생성자에 해당하는 코드를 찾아 내고, 그 코드를 호출하는 기계 명령어를 생성합니다. 다음 줄에는 int x = foo.bar이라고 쓰십시오. 여기서 컴파일러는 int에 대한 스택 공간을 할당하는 컴퓨터 명령어를 작성한 다음 데이터 구조를 SomeClass으로 봅니다. 해당 데이터 구조는 foo 개체의 시작 부분에서 바이트 단위로 오프셋을 bar으로 알려줍니다. 그런 다음 컴파일러는 bar에 해당하는 바이트를 x의 메모리에 복사하는 컴퓨터 코드를 씁니다. 이 기계 코드는 모두 실행 파일에 기록됩니다. 컴파일이 완료되면

일반적으로, 데이터 SomeClass를 나타내는 구조와 다른 정의는 버려된다. 당신이 남긴 것은 단지 일련의 기계 지침 일뿐입니다. 이 지침은 실제로 이 실행될 때을 실행하면 SomeClass의 생성자와 foo.barx으로 복사하는 코드가 개체 구조에 대한 명확한 지식없이 CPU에 의해 실행됩니다.

이것은 일반적인 경우입니다. 이 디버거에서 및 최적화에 대한 귀하의 코드를 실행하면에 대한 특별한 경우가 있지만, 이것은 일반적으로 발생하는입니다.

6

컴파일러는 foo의 주소가 있습니다. 해당 주소에는 멤버 변수 (sizeof(SomeClass))를위한 충분한 공간이 있으며 여기에는 약간의 패딩이 포함됩니다.

그것은 줄은 클래스의 일부 위치 (일반적으로이 선언 된 순서, 플러스 상속과 같은 몇 가지 다른 마법)에있다 '것을 알고 있으며, 오프셋로 이동합니다. 이다

: 컴파일러가 SomeClass에 대한 정의를 볼 때

런타임에서
struct SomeClass 
{ 
    short s; 
    float f; 
    int bar; 
    char *c; 
} 

// pseudo-code: 
&SomeClass.bar == (&SomeClass) + sizeof(short) + sizeof(float); 

, 그것은 데이터를 가져오고 x

+1

"컴파일러에는 foo의 주소가 있습니다."- 일반적으로 foo는 자동 변수이므로 일부 스택 포인터에 비해 foo의 오프셋이 있습니다. –

+0

아직 주소는 무엇입니까 :) – GManNickG

+2

이것은 기술적으로 부정확합니다. 컴파일러는 (보통) foo.bar를 x에 할당하지 않습니다. 컴파일러는 foo.bar를 런타임에 x에 할당하는 기계 명령어를 생성합니다. –

1

당신은 컴파일시 모든 클래스 (설명을 단순화하기 위해) 구조체에 전원이 켜져 있는지 생각해야한다, 그래서 당신은

class Foo 
{ 
    int x, y, z; 
    char bar[10]; 
    ... etc ... 
} 

이있는 경우 그들은이 경우, 지정된 크기를 가지는 구조체로 전환된다 4 * 3 + 10 바이트. 그런 다음 정렬에 따라 더 편리한 방법으로 정렬합니다. 예를 들어 오프셋 4에서 속성 y를 찾을 수 있으며 주소 8에서 z를 찾을 수 있습니다.

다음은 쉽습니다. 할당에 관련된 클래스의 주소에 4를 추가하면 y 주소 등을 얻을 수 있습니다.

+2

4 대신에 sizeof (int)를 사용하십시오. 'int'는 꼭 4 바이트는 아닙니다. – GManNickG

1

컴파일러는 컴파일 할 때만 이러한 클래스 메타 데이터를 저장합니다. 귀하의 첫 번째 질문, 어떻게 막대의 가치를 검색합니까, 실제로는 상당히 복잡합니다. foo 객체의 bar의 오프셋을 계산 한 다음 그 위치에서 메모리를 읽는 것으로 생각할 수 있습니다. 그러나 x가 실제로 어떻게 사용되는지에 따라 훨씬 다른 것을 할 수 있습니다. 일부 상황에서는 'x'가 컴파일 된 코드에 전혀 표시되지 않을 수도 있습니다.

4

컴파일러에는 컴파일러가 SomeClass의 각 멤버에 액세스하는 방법을 알려주는 데이터 구조가 있습니다. 단순한 경우에는 그냥 오프셋이 될 것이지만, 사소한 상속을받는다면 더 많은 것이있을 수 있습니다.

식을 처리하기 위해 컴파일러는이 내부 데이터를 참조하여 (결국) 적절한 컴퓨터 코드를 내 보냅니다. 런타임에이 구조체는 버려 질 것이고 나머지는 foo의 주소부터 시작하여 필요한 것을 수행하기 위해 생성 된 코드입니다. 그러나 막대에 대한 포인터를 갖는 포인터가있는 경우 bar 멤버에 액세스하는 방법에 대한 세부 정보가 포인터 값에 캡슐화됩니다 (아마도 오프셋, 어쩌면 좀 더 복잡한).