Можно ли сделать переменную действительно доступной только для чтения в C ++? - PullRequest
4 голосов
/ 09 июля 2020

При использовании квалификатора const переменная должна быть сделана доступной только для чтения. Например, int с пометкой const нельзя присвоить:

const int number = 5; //fine to initialize
number = 3; //error, number is const

На первый взгляд кажется, что это делает невозможным изменение содержимого number. К сожалению, на самом деле это возможно. В качестве примера можно использовать const_cast (*const_cast<int*>(&number) = 3). Это неопределенное поведение , но это не гарантирует, что number фактически не будет изменен. Это может привести к ошибке sh в программе, но также можно просто изменить значение и продолжить.

Можно ли сделать так, чтобы невозможно изменить переменную?

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

Ответы [ 5 ]

3 голосов
/ 09 июля 2020

Нет, это не касается языка программирования. Любая защита от «доступа» является лишь поверхностной и существует только во время компиляции.

Память компьютера всегда может быть изменена во время выполнения, если у вас есть соответствующие права. Ваша ОС может предоставить вам средства для защиты страниц памяти, например VirtualProtect () под Windows.

(Обратите внимание, что «злоумышленник» может использовать те же средства для восстановления доступ, если он имеет на это право)

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

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

2 голосов
/ 09 июля 2020

Хотя большинство ответов в этом потоке правильные, но они относятся к const, в то время как OP запрашивает способ определения и использования постоянного значения в исходном коде. Мой хрустальный шар говорит, что OP ищет константы symboli c (инструкции препроцессора #define).

#define NUMBER 3
//... some other code
std::cout<<NUMBER;

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

Просто имейте в виду, что константные переменные видны отладчикам, а символьные c константы - нет, но они не требуют дополнительной памяти. Еще один критерий - проверка типов, которая отсутствует в случае констант symboli c, а также для макросов.

2 голосов
/ 09 июля 2020

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

Значение const x в основном таково:

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

Это сильно отличается от:

Эй, компилятор, пожалуйста, предотвратите любые изменения в x в этой области.

Даже если вы сами не напишете никаких const_cast - компилятор все равно не будет предполагать, что const 'ed сущности не изменятся. В частности, если вы используете функцию

int foo(const int* x);

, компилятор не может предположить, что foo() не изменяет память, на которую указывает x.

Вы можете использовать свое значение без переменная

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

  • перечисление с одним значением: enum : int { number = 1 }.
  • препроцессор: #define NUMBER 1 <- Не рекомендуется </li>
  • функция: inline int get_number() { return 1; }

Вы можете использовать реализацию / платформу c особенности

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

const char* my_str = "Hello world";
const_cast<char*>(my_str)[0] = 'Y';

Ваш процесс, скорее всего, завершится ошибкой с сообщением, например:

Segmentation fault (core dumped)
1 голос
/ 09 июля 2020

Невозможно указать, какой код не соответствует спецификации.

В вашем примере number действительно константа. Вы правильно заметили, что изменение его после const_cast будет неопределенным поведением. И действительно, изменить его в правильной программе невозможно.

1 голос
/ 09 июля 2020

Если вы знаете программу во время компиляции, вы можете поместить данные в постоянную память. Конечно, кто-то может обойти это, но безопасность - это слои, а не абсолют. Это усложняет задачу. C ++ не имеет понятия об этом, поэтому вам нужно будет проверить полученный двоичный файл, чтобы увидеть, произошло ли это (это может быть написано как проверка после сборки).

Если у вас нет значения в во время компиляции ваша программа зависит от возможности изменять / устанавливать ее во время выполнения, поэтому вы принципиально не можете предотвратить это. const, поэтому код компилируется в предположении, что он не изменится / программистам сложнее случайно изменить его.

Вы также можете найти constexpr здесь интересный инструмент для изучения.

...