Изменение значения volatile const — G против Visual Studio 2019

#c #constants #g #visual-studio-2019 #volatile

#c #константы #g #visual-studio-2019 #volatile

Вопрос:

Итак, у меня есть следующий фрагмент (и веская причина для этого):

 #include <iostream>

volatile const float A = 10;

int main() {
    volatile const float* ptr = amp;A;
    float* safePtr = const_cast<float*>(ptr);
    *safePtr = 20;

    std::cout << A << std::endl;

    return 0;
}
  

Под G v8.2.0 (из MinGW suite) эта программа отлично компилируется и выводит 20 результаты, как ожидалось. В версии VS2019 он компилируется, но выдает исключение во время выполнения — Exception thrown at 0x00007FF7AB961478 in Sandbox.exe: 0xC0000005: Access violation writing location 0x00007FF7AB969C58 .

Есть ли способ заставить VS2019 вести себя так же, как G ? И как это сделать с помощью CMake?

Комментарии:

1. «и за этим стоит веская причина», это проблема XY. Какую проблему вы пытаетесь решить с помощью этого кода?

2. @n.’местоимения’m. Я кодирую игру, и у меня есть много констант, которые требуют точной настройки с течением времени. Я хочу, чтобы компилятор проверял правильность const в моем обычном коде, но я также хочу иметь возможность редактировать эти константы во время выполнения в режиме отладки.

3. Таким образом, такая псевдоконстанта представляет собой объект, который представляет два интерфейса: интерфейс наблюдателя (для большей части кода) и интерфейс редактирования (для вашей отладочной части кода). Менее причудливыми словами, получатель и установщик.

4. Что нарушит работу API, возможно, предотвратит оптимизацию компилятора при сборке выпуска и усложнит код для определения простых числовых констант. Большую часть сегодняшнего дня я потратил на то, чтобы найти способ, который не привел бы к серьезным изменениям как в релизной, так и в отладочной версиях кода, но я начинаю сомневаться, что у C есть для этого возможность.

5. На данный момент наиболее близким вариантом к тому, что мне нужно, которые я нашел, являются inline переменные из C 17. Они не обеспечивают проверки правильности const, но кроме этого могут быть максимально легко интегрированы в существующую кодовую базу.

Ответ №1:

Все приведенные ниже стандартные ссылки относятся к N4659: рабочий проект после Kona в марте 2017 года / C 17 DIS.


В соответствии с [dcl.type.cv ]/ 4, ваша программа имеет неопределенное поведение

За исключением того, что любой член класса, объявленный изменяемым, может быть изменен, любая попытка изменить объект const в течение его срока службы приводит к неопределенному поведению. [ Пример:

 // ...

const int* ciq = new const int (3);  // initialized as required
int* iq = const_cast<int*>(ciq);     // cast required
*iq = 4;                             // undefined: modifies a const object
  

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

Ответ №2:

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

const_cast позволяет формировать ссылку или указатель на неконстантный тип, который фактически ссылается на объект const, или ссылку или указатель на энергонезависимый тип, который фактически ссылается на энергозависимый объект. Изменение объекта const через неконстантный путь доступа и обращение к изменчивому объекту через энергонезависимое значение glvalue приводит к неопределенному поведению.

Вы не должны пытаться заставить это работать, игнорируя проблему, я предполагаю, что вы запускаете программу в VS в режиме отладки, поэтому она улавливает ошибку, которой нет в g , но если вы запустите свою программу через отладчик, вы, вероятно, увидите ту же проблему, хотя это не гарантируется в соответствии с характером неопределенного поведения.

Способ исправить код, а не игнорировать проблему.

Комментарии:

1. «[…] но если вы запустите свою программу через отладчик, вы увидите ту же проблему». — такой гарантии нет. Поскольку программа OPs имеет UB, все исключено, и любой анализ такой программы может только усилить ошибочное представление о том, что неопределенное поведение действительно можно обосновать (поскольку может показаться, что оно делает то, что можно ожидать от той же программы без UB).

2. @dfri, да, я перефразирую.

3. VS2019 правильный. … ну, технически они оба верны, так как с UB может случиться все, что угодно. Просто пытаюсь быть немного понятнее здесь.

4. @MikeVine, я считаю, что вы правы, я хочу подчеркнуть, что проблему нельзя игнорировать, я перефразировал ее.

5. @doomista, const определенные значения не могут быть изменены во время выполнения безопасным способом при любых настройках, некоторые компиляторы сохраняют их в разделах памяти, доступных только для чтения, и у вас происходит сбой программы, некоторые нет, и ваша программа, похоже, работает правильно, это то, что стандарт не допускает, я знаю, что нет способа сделать что-то, как вы просите. На сайте есть множество тем по этому вопросу, возможно, среди них у кого-то есть решение вашей проблемы.

Ответ №3:

Как указано, вы не можете юридически изменять объекты const…

Но у вас может быть постоянная ссылка на неконстантный объект:

итак, вы могли бы использовать следующее:

 const floatamp; A = *([]() { static float a = 10; return amp;a; }());
// const floatamp; A = []() -> floatamp; { static float a = 10; return a; }();


int main() {
    float* safePtr = const_cast<float*>(amp;A);
    *safePtr = 20;

    std::cout << A << std::endl;
}
  

( volatile Ни то, ни другое не требуется).

Комментарии:

1. Это довольно крутая идея, однако ее нельзя использовать как замену глобальной const, помещенной в общий файл заголовка. Подобное решение было бы примерно таким: extern int A_ORIG; volatile const int * const A = amp;A_ORIG; но это уже нарушает существующий API, поскольку превращает const в указатель. 🙁

2. Если вы боитесь нарушения ODR, вы можете использовать класс template вместо lambda.