Как компилятор различает вложенные объекты, если они имеют одинаковый адрес?

В следующем примере (попробуйте Вот)

#include <iostream>
using namespace std;

struct a {
struct b {
int b1;
};
b a1;
int a2;
};
int main() {
a test;
test.a1.b1 = 5;
test.a2 = 6;

std::cout<<&test<<" "<<&(test.a1);
// your code goes here
return 0;
}

И структура, и ее структура nestd имеют одинаковое расположение в памяти. Это имеет смысл, поскольку первый элемент, который будет храниться в памяти, является частью вложенной структуры.

Доказательство: 0x7ffd895f86e0 0x7ffd895f86e0

Мой вопрос: как компилятор узнает, какие типы хранятся в этом месте, и есть ли какие-либо издержки от отслеживания такой информации во время выполнения, которую следует ожидать?

0

Решение

Как насчет этого:

struct a {
int x;
struct b {
int b1;
};
b a1;
int a2;
};

У них одинаковый адрес? Нет, не потому, что они разные, а потому, что «struct» не имеет бинарного значения (перед тем, как разбить это, продолжайте читать). Когда ваша программа компилируется, все, что имеет значение, это переменные внутри ваших структур. Язык программирования имеет эту поверхностную вещь, называемую «структура», чтобы упростить вам задачу. Но это не реально, если вы не сделаете что-то, что требует, чтобы это обрабатывалось как одна вещь (например, копирование), и даже тогда сгенерированный двоичный код (для времени выполнения) будет представлять только элементы, которые должны быть скопированы как в целом, а не «структура», как таковая.

Когда вы создаете экземпляр a вот как это выглядит в памяти:

int x - int b1 - int a2

Это блоки в памяти с целыми числами. Это не структура.

Вы можете проверить это с помощью указателей. В вашем коде:

*(int*)(&test) //is b1
*((int*)(&test)+1) //is a2

Итак, вы видите, что в памяти только два целых числа.

PS: обратите внимание, что все это предполагает, что мы не имеем дело с полиморфизмом, который добавляет больше блоков памяти, которые представляют vtable. Это история для другого дня.

2

Другие решения

Забудьте на мгновение, что вы имеете дело со структурами. Как компилятор знает, что определенная область памяти содержит int или float? В каком-то смысле это не так. Но в рамках программы, переменные имеют тип и это тип сообщает компилятору, какие операции допустимы для этой переменной. Неважно, каков адрес объекта; важно то, какой тип программа говорит. Так:

int i = 3;
i = i + 1;

Компилятор знает, как сделать это дополнение, потому что программа сказала, чтобы обработать область памяти с именем i как int значение.

float f = 4.0;
f = f + 1;

Компилятор знает, как сделать это дополнение, потому что программа сказала, чтобы обработать область памяти с именем f как float значение.

В вашем примере test.a1.b1 имеет тип int потому что программа так сказала. А также test.a1 имеет тип a :: bbecause the program said so. Andтестовое заданиеhas typeа` потому что программа так сказала.

1

Давайте «нарисуем», как структура выглядит в памяти (вместе с «указателями» на нее):

+----+----+
| а1 | а2 |
+ ---- + ---- +
^ ^
| |
|    test.a2
|
тестовое задание
|
test.a1

Надеюсь, это должно прояснить, как две разные структуры могут занимать одну и ту же память.

Следует отметить, что это только для структур с не виртуальными функциями. Виртуальные функции могут вызывать включение других скрытых элементов в объекты.

0

На самом деле, именно вы явно указываете компилятору, какой тип хранится в данном месте, написав такие выражения, как &тест и &(Test.a1).

0
По вопросам рекламы [email protected]