2016-09-14 2 views
4

Я прочитал, что ссылка является просто псевдонимом переменной, существующей в таблице символов. Рассмотрим следующий кодC++ do ссылки занимают память

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"; 
} 

Для выхода я получаю

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

Если ссылка не занимает память в стеке, почему память смещена. Например. В тесте функции локальная переменная 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++ не переместит место хранения указателя, который поддерживает ссылку.

Обратите внимание, что, если вам не нужен адрес объекта с автоматическим хранилищем («в стеке»), компилятор не обязан фактически помещать его в стек. Он может полностью жить в реестрах, или он может быть полностью оптимизирован. Например, с помощью этой функции:

int foo(int a, int b) { return a + b; } 

На x86_64 с вызывающей конвенцией System V, a передается в регистре RDI, b передается в rsi регистре, результат вычисляется в rax, а функция Безразлично Не нужно прикасаться к стеку для любых его значений.

Смежные вопросы