Почему C++ запрещает создание допустимых указателей с допустимого адреса и типа?

Если вы знаете две части информации:

  1. Адрес памяти.
  2. Тип объекта хранится в этом адресе.

Тогда у вас есть все необходимое для ссылки на этот объект:

#include <iostream>
using namespace std;

int main()
{
    int x = 1, y = 2;
    int* p = (&x) + 1;
    if ((long)&y == (long)p)
        cout << "p now contains &y\n";
    if (*p == y)
        cout << "it also dereference to y\n";
}

Однако это не разрешено стандартом C++. Он работает в нескольких компиляторах, которые я пробовал, но это неопределенное поведение.

Вопрос в том, почему?

4 ответа

Решение

Это наносит ущерб оптимизации.

void f(int* x);

int g() {
    int x = 1, y = 2;
    f(&x);
    return y;
}

Если вы действительно можете "угадать" адрес y от xадрес, затем вызов f может изменить y и так return оператор должен перезагрузить значение y из памяти.

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

Если вы хотите рассматривать указатели как числовой тип, сначала вам нужно использовать std::uintptr_tне long, Это первое неопределенное поведение, но не то, о котором вы говорите.

Он работает в нескольких компиляторах, которые я пробовал, но это неопределенное поведение.

Вопрос в том, почему?

Итак, раздел комментариев отключился, когда я вызвал это неопределенное поведение. Это на самом деле неопределенное поведение (определенное реализацией).

Вы пытаетесь сравнить два явно не связанных указателя:

  • &x + 1
  • &y

Указатель &x+1 указатель на один конец Стандарт позволяет вам иметь такой указатель, но поведение определяется только тогда, когда вы используете его для сравнения с указателями на основе x, Поведение не указывается, если вы сравниваете его с чем-либо еще: [expr.eq § 3.1]

Компилятор свободен поставить y где угодно, в том числе и в реестре. Таким образом, нет никакой гарантии, что &y а также &x+1 относятся к.

В качестве упражнения для того, кто хочет показать, является ли это фактически неопределенным поведением или нет, возможно, начните здесь:

  • http://eel.is/c++draft/basic.stc.dynamic.safety:

    Целочисленное значение является целочисленным представлением надежно полученного указателя, только если его тип по крайней мере такой же, как std:: intptr_t, и это одно из следующего:...

    3.4 результат аддитивной или побитовой операции, один из операндов которой является целочисленным представлением безопасно полученного значения указателя P, если этот результат, преобразованный с помощью reinterpret_cast, сравнивается равным безопасно полученному указателю, вычисляемому из reinterpret_cast (P).

  • [basic.compound § 3.4]:

    Примечание. Указатель за концом объекта ([expr.add]), как считается, не указывает на несвязанный объект типа объекта, который может находиться по этому адресу.

Если вы знаете адрес и тип объекта, и ваша реализация имеет ослабленную безопасность указателя http://eel.is/c++draft/basic.stc.dynamic.safety, тогда будет законно просто получить доступ к объекту по этому адресу через соответствующее значение l, я думаю.

Проблема в том, что стандарт не гарантирует, что локальные переменные одного и того же типа размещаются непрерывно, а адреса увеличиваются в порядке объявления. Таким образом, вы не можете получить адрес y на основе этого вычисления вы делаете с адресом x, Кроме того, арифметика указателей приведет к неопределенному поведению, если вы пройдете более одного элемента за объектом ( [expr.add]). Так что пока (&x) + 1 еще не определено поведение, просто акт даже вычислений (&x) + 2 было бы…

Код допустим в соответствии со стандартом C++ (т.е. должен компилироваться), но, как вы уже заметили, поведение не определено. Это связано с тем, что порядок объявления переменных не означает, что они будут расположены в памяти одинаково.

Другие вопросы по тегам