2016-09-14 1 views
4

그 참조는 기호 테이블에있는 변수의 별칭 일뿐입니다. 참조가 스택 메모리를 차지하지 않으면 내가 C++ do references 메모리를 점유 함

0039F740 
0039F848 
0039F748 
0039F74C 
0039F848 
0039F848 
0039F830 

을받을 출력을 위해 다음 코드

int main() 
{ 
    int y = 6; 
    int &z = y; 
    int k = 43; 
    test(2,y,5,78); 
    cout << &y << "\n"; 
    cout << &z << "\n"; 
    cout << &k << "\n"; 
} 

void test(int a,int & x, int g, int h) 
{ 
    cout << &a << "\n"; 
    cout << &x << "\n"; 
    cout << &g << "\n"; 
    cout << &h << "\n"; 
} 

을 고려, 왜 메모리 오프셋되고있다. 예 : 함수 테스트에서 지역 변수 a는 0039F740에 있지만 g는 0039F748에 있습니다. 0039F744에 있어야하지 않습니까?

누군가가 깊이 설명해 주시겠습니까?

+3

참조가 저장되어야하는지 여부는 * 지정되지 않았습니다. 컴파일러 작성자가 어떤 상황에서도 참조를 구현하는 방법을 결정합니다. –

답변

1

함수에는 네 개의 매개 변수가 있습니다.

각 매개 변수는 함수에 전달되어야합니다.

매개 변수 중 하나가 참조라는 사실은이 기본 사실을 변경하지 않습니다. 추가 공간은 함수에 대한 참조 매개 변수입니다.

이 문맥에서 참조는 실제로 위장에있는 포인터입니다. 로컬 범위의 객체를 참조하는 로컬 범위의 참조가있는 경우 대부분의 C++ 컴파일러는 참조를 실제 메모리를 차지하지 않도록 실제로 최적화합니다.

그러나 함수 호출은 완전히 새로운 볼 게임입니다. 이 함수는 어떤 객체에 대한 참조를받을 것으로 기대합니다. 함수는 참조로 전달되는 내용을 텔레파시로 알 수 없습니다. 함수를 호출하는 모든 것이 참조 매개 변수를 제공합니다. 이 정보를 전달하기 위해 몇 바이트가 필요하다는 것은 말할 필요도 없습니다. 즉, 참조로 전달 된 객체의 주소 (최근에 포인터에 대해 언급 한 적이 있습니까?)

함수가 static 범위 (외부 연결 없음)로 선언되었고 컴파일을 위해 충분히 적극적인 최적화 수준이 선택되면 C++ 컴파일러가 함수 호출을 인라인하고 참조 매개 변수를 멀리 떨어져 최적화 할 수 있습니다.

외부 링키지가있는 함수를 선언하면 일반적으로 컴파일러가 함수 호출을 인라인하려고하지 않아도됩니다. 그것은 진행하고 각기 다른 매개 변수를 가질 것으로 기대되는 본격적인 독립형 함수를 생성합니다.

좀 더 일반적인 방법으로 질문에 대답하십시오 : C++ 표준은 참조가 메모리를 차지할 필요는 없지만 그렇게해서는 안되는 것을 요구하지는 않습니다. C++ 컴파일러는 결과가 정확하고 예상되는대로 코드를 자유롭게 컴파일 할 수 있습니다. 특정 상황에서 C++ 컴파일러가 참조를 최적화하여 자체의 개별 객체로 실제로 존재하지 않도록하는 방법을 찾는 경우 자유롭게 수행 할 수 있습니다. 그러나 그렇게 할 필요는 없습니다.

+0

로컬 변수 z가 실제 메모리를 차지하지 않는다는 것을 의미합니까? 그리고 왜 지방 변수 k가 0039F830에 있습니까? – TFK

+0

컴파일러가 무엇을 하느냐에 따라 달라질 수도 있습니다. 또한 컴파일러는 특정 메모리 주소를 변수에 할당 할 필요가 없습니다. 컴파일러는 하드웨어 관련 정렬 이유로 인해 로컬 객체를 그런 방식으로 저장하도록 선택할 수 있습니다. –

+0

참조로 전달할 때 후드 아래에 여전히 참조 주소를 스택에 넣고 있다고 가정하는 것이 안전할까요? – TFK

0

참조 기호는 "기호 테이블의 다른 것에 대한 별칭"보다 더 복잡합니다. 사실, 그 정의는 종종 적용되지 않습니다. 예를 들어, 참조 매개 변수는 하나 이상의 별개의 인수 값을 사용하여 함수가 호출되는 것을 방지하기 때문에 "기호 테이블의 다른 항목"으로 별칭을 지정할 수 없습니다.

표준은 어떻게해야하는지에 대해서는 말하지 않지만, 일반적인 참조 구현은 단지 포인터를 사용하는 것입니다. int& x 인 경우 x*(pointer)이고 &x(pointer)을 반환합니다.포인터는 메모리를 차지하지만 잘 정의 된 C++ 연산은 참조를 뒷받침하는 포인터의 저장 위치를 ​​나타낼 수 없습니다.

자동 저장소가있는 개체의 주소 ("스택에있는")를 가져올 필요가 없다면 컴파일러는 실제로 스택에 넣을 필요가 없습니다. 그것은 전적으로 레지스터에 존재할 수도 있고 완전히 최적화 될 수도 있습니다. 예를 들어,이 기능 :

는 시스템 V 호출 규칙과 x86_64의 온
int foo(int a, int b) { return a + b; } 

abrsi 레지스터에 전달되고, 그 결과가 rax 계산되면, RDI 레지스터에 전달되고, 기능 케이 그 값에 대해 스택을 만질 필요가 없습니다.