const int *var;
const
является контракт. Получив параметр const int *
, вы «расскажете» вызывающему, что вы (вызываемая функция) не будете изменять объекты, на которые указывает указатель.
Ваш второй пример явно нарушает этот договор, отбрасывая спецификатор const и затем изменяя объект, на который указывает полученный указатель. Никогда этого не делай.
Этот «контракт» применяется компилятором. *dummy = 1
не компилируется. Бросок - это способ обойти это, сообщая компилятору, что вы действительно знаете, что делаете, и позволяете вам это делать. К сожалению, «я действительно знаю, что я делаю», обычно не так.
const
также может использоваться компилятором для выполнения оптимизации, иначе он не мог бы этого сделать.
Неопределенное поведение Примечание:
Пожалуйста, обратите внимание, что в то время как сам литая технически правовой, изменение значения задекларирован как const
является Неопределенное поведение. Так что технически исходная функция в порядке, если переданный ей указатель указывает на данные, объявленные изменчивыми. Иначе это неопределенное поведение. подробнее об этом
в конце поста
Что касается мотивации и использование позволяет принимать аргументы strcpy
и memcpy
функции:
char* strcpy(char* dest, const char* src);
void* memcpy(void* dest, const void* src, std::size_t count);
strcpy
работает от символьных строк, memcpy
работает с общими данными.В то время как я использую STRCPY, как, например, следующее обсуждение точно так же для обоих, но с char *
и const char *
для strcpy
и void *
и const void *
для memcpy
:
dest
является char *
, потому что в буфере dest
функция поместит копию. Функция будет изменять содержимое этого буфера, поэтому оно не является константой.
src
const char *
потому что функция только считывает содержимое буфера src
. Он не изменяет его.
Только взглянув на объявление функции, вызывающий может утверждать все вышеперечисленное. По контракту strcpy
не будет изменять содержимое второго буфера, переданного в качестве аргумента.
const
и void
ортогональны. То есть все сказанное выше о const
относится к любому типу (int
, char
, void
...)
void *
используется в C для «общих» данных.
Еще на Неопределенное поведение:
Случай 1:
int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object
*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable
Случай 2:
const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.
Я начал с этими примерами, поскольку их легче понять. Отсюда только один шаг, чтобы аргументы функции:
void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}
Case 1:
int a = 0;
foo(&a); // the write inside foo is legal
Случай 2:
int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior
Снова я должен подчеркнуть: если вы действительно не знаете, что вы и все люди, работающие в настоящем и будущем в коде, являются экспертами и понимают это, и у вас есть хорошая мотивация, если все вышеперечисленное не выполнено, никогда не отбрасывает постоянство!
'const T *' означает, что данные, указываемые указателем to_ указателем, являются константами. Второй - очень хрупкий, поскольку он отбрасывает const. –
@ColonelThirtyTwo Но из того, что я читал в других сообщениях stackoverflow, не const void * часто используется для предотвращения изменения данных? Но мне кажется, что путем литья его можно очень легко модифицировать. – MoneyBall
@MoneyBall да, но кастинг - вот так. Вот почему кастинг опасен - я могу взять ваш «const int *» и передать его в «int64_t *» и SIGSVF или испортить другие данные. Проблема заключается в том, что * casting * не объявляет const. –