указатель на структуру или класс против указателя на первое поле

Недавно я попытался отладить небольшую программу, выводя значения нескольких указателей на консоль. Первым был адрес памяти структуры, а остальные были адресами памяти ее полей. Укороченная версия кода выглядит следующим образом:

#include <iostream>

struct testingPointers
{
int i;
float f;
double d;
} test;

int main()
{
std::cout << &test << '\n' << &(test.i) << '\n' <<
&(test.f) << '\n' << &(test.d);
}

И вывод:

0x681110
0x681110
0x681114
0x681118

(очевидно, точные значения различны для разных прогонов, но они всегда имеют одинаковые позиции относительно друг друга).

Я запутался, потому что значение первого указателя — ячейка памяти test— так же, как у второго (первое поле test). Означает ли это, что объекты не имеют реального уникального адреса памяти и что указатель на структуру или класс просто указывает на его первое поле? Если так, то как нравятся заявления

a.b
a->b
a.b()

имеет смысл, если a на самом деле это только его первое поле, и, следовательно, не имеет никаких полей или методов?

6

Решение

Класс или структура просто описывает набор полей, которые должны храниться вместе в памяти и иметь определенные семантические отношения между ними и некоторыми операциями, которые над ними работают. В простом случае нет ничего более важного для содержимого объекта типа класса в памяти, чем элементы, из которых он состоит (и некоторые отступы). Когда у вас есть testingPointers объект в памяти, это действительно просто int, float и double, Концепция класса использовалась только для генерации правильного исполняемого кода — он не существует во время выполнения (по крайней мере, не для этой цели).

Важной частью стандарта относительно того, могут ли объекты совместно использовать адреса памяти, является §1.8 / 6:

Если объект не является битовым полем или подобъектом базового класса нулевого размера, адрес этого объекта является адресом первого байта, который он занимает. Два объекта, которые не являются битовыми полями, могут иметь один и тот же адрес, если один является подобъектом другого, или если хотя бы один является подобъектом базового класса нулевого размера, и они имеют разные типы; в противном случае они должны иметь разные адреса.

Мы можем сделать вывод из этого, потому что член test.i подобъект test, они вполне могут иметь один и тот же адрес.

Как только вы загляните внутрь всех объектов вашей программы настолько глубоко, насколько сможете, вы действительно получите большую коллекцию скалярных значений и смежных битовых полей. Они известны как места памяти в стандарте. Это вещи, которые действительно занимают место. Все остальные ваши объекты каким-то образом состоят из них.

место в памяти является либо объектом скалярного типа, либо максимальной последовательностью смежных битовых полей, имеющих ненулевую ширину. [ Замечания: Различные функции языка, такие как ссылки и виртуальные функции, могут включать дополнительные области памяти, которые не доступны для программ, но управляются реализацией. — конечная нота ]

5

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

Адрес объекта всегда должен быть адресом первого нестатического члена в этом объекте. Цитирование из стандарта (C ++ 11-9.2-20):

Указатель на объект структуры стандартной компоновки, соответствующим образом преобразованный с использованием reinterpret_cast, указывает на его начальный элемент (или, если этот элемент является битовым полем, то на модуль, в котором он находится), и наоборот. [Примечание: Следовательно, в объекте структуры стандартной компоновки может быть безымянный отступ, но не в его начале, что необходимо для достижения соответствующего выравнивания.

Требования к стандартный макет упоминаются здесь: StandardLayoutType.

Это, безусловно, может быть применено через вложение. Стандарт не делает исключений для тип первого члена Кроме для битовых полей. т.е .:

class X
{
public:
int x;
};

class Y
{
public:
X x;
int y;
};

Y yobj;

По стандарту, &yobj == &yobj.x == &yobj.x.x,

6

Просто чтобы прояснить ваши заблуждения:

1). Значение первого указателя — ячейка памяти теста — такое же, как и у второго (первое поле теста).
Адрес Struct и его первого поля должны быть одинаковыми, так как struct — это ничто иное, как совокупность его полей непрерывно.

введите описание изображения здесь

Вы также можете рассмотреть случай массивов, чтобы еще больше упростить понимание, когда адрес массива, очевидно, будет равен первому элементу (полю) массива.

2). Означает ли это, что объекты не имеют реального уникального адреса памяти и что указатель на структуру или класс просто указывает на его первое поле?
Я думаю, что вы путаете это с JAVA, где объект всегда размещается в куче. В C ++ struct / class всегда размещается в стеке, если только это не динамическое выделение памяти (с использованием оператора ‘new’), где объект размещается в куче, а переменная-указатель (в стеке) будет указывать на этот объект в куче. Следовательно, в первом случае переменная структуры всегда будет иметь тот же адрес, что и ее первый элемент (поле).

Надеюсь, это поможет.

3

Структура в памяти состоит не более чем из полей, соединенных вместе. Может быть заполнение перед структурой и / или между полями, основанное на потребностях выравнивания, но обычно нет никаких дополнительных «вещей» перед первым полем. Таким образом, первое поле и сама структура имеют один и тот же адрес.

Помните, что в C типы существуют только во время компиляции.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector