Хотя это правда , что поведение определено корректно - это не правда , что компиляторы могут «оптимизировать для сопзЬ» в том смысле , что вы имеете в виду.
То есть компилятору не разрешается предполагать, что только из-за того, что параметр является a const T* ptr
, указанная память ptr
не будет изменена через другой указатель. Указатели даже не должны быть равны. Это const
обязательство, а не гарантия - ваше обязательство (= функция) не вносить изменения через этот указатель.
Чтобы действительно иметь такую гарантию, вам нужно пометить указатель restrict
ключевым словом. Таким образом, если вы скомпилируете эти две функции:
int foo(const int* x, int* y) {
int result = *x;
(*y)++;
return result + *x;
}
int bar(const int* x, int* restrict y) {
int result = *x;
(*y)++;
return result + *x;
}
foo()
функция должна прочитать дважды из x
, в то время как bar()
только нужно прочитать его один раз:
foo:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, DWORD PTR [rdi] # second read
ret
bar:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, eax # no second read
ret
Смотрите это в прямом эфире GodBolt.
restrict
является только ключевым словом в C (начиная с C99); к сожалению, он до сих пор не введен в C ++ (по плохой причине, так как его сложнее ввести в C ++). Многие компиляторы поддерживают его, как, впрочем, и __restrict
.
Итог: компилятор должен поддерживать ваш «эзотерический» вариант использования при компиляции f()
и не будет иметь никаких проблем с ним.
Смотрите этот пост относительно вариантов использования для restrict
.
const
не является «вашим обязательством (= функция) не вносить изменения через этот указатель». Стандарт C позволяет функции удалятьconst
через приведение, а затем изменять объект в результате. По сути,const
это просто рекомендация и удобство для программиста, помогающее избежать непреднамеренного изменения объекта.memcpy
иstrcpy
объявляются сrestrict
аргументами, аmemmove
нет - только последний допускает перекрытие между блоками памяти.Это хорошо определено (в C ++, больше не уверен в C), с и без
const
квалификатора.Первое, на что нужно обратить внимание - это строгое правило псевдонимов 1 . Если
src
иdst
указывает на один и тот же объект:char*
иchar const*
не совместимы.char*
иchar const*
похожи.Что касается
const
классификатора, вы можете утверждать, что, поскольку, когдаdst == src
ваша функция эффективно изменяет то,src
на что указывает,src
не следует квалифицировать какconst
. Это не так, какconst
работает. Необходимо рассмотреть два случая:const
, как, напримерchar const data[42];
, его изменение (прямо или косвенно), приводит к неопределенному поведению.const
объект определены, напримерchar const* pdata = data;
, можно изменить базовый объект, если он не был определен какconst
2 (см. 1.). Таким образом, следующее четко определено:1) Что такое строгое правило псевдонимов?
2) Является ли
const_cast
безопасно?источник
char*
иchar const*
не совместимы._Generic((char *) 0, const char *: 1, default: 0))
оценивает в ноль.const
объект определена» неверна. Вы имеете в виду, что когда определена ссылка или указатель наconst
-качественный тип , это не означает, что объект, на который он указывает, не может быть изменен (различными способами). (Если указатель действительно указывает наconst
объект, это означает, что объект действительноconst
по определению, поэтому поведение при попытке изменить его не определено.)language-lawyer
. Точность - это ценность, которую я лелею, но я также знаю, что она усложняется. Здесь я решил пойти на простые и понятные предложения, потому что считаю, что это именно то, что хотел OP. Если вы думаете иначе, пожалуйста, ответьте, я буду среди первых, кто проголосует за это. В любом случае, спасибо за ваш комментарий.Это хорошо определено в C. Строгие правила псевдонимов не применяются
char
ни к типу, ни к двум указателям одного типа.Я не уверен, что вы подразумеваете под "оптимизировать для
const
". Мой компилятор (GCC 8.3.0 x86-64) генерирует одинаковый код для обоих случаев. Если вы добавитеrestrict
спецификатор к указателям, то сгенерированный код будет немного лучше, но это не сработает для вашего случая, указатели будут такими же.(С11 §6.5 7)
В этом случае (без
restrict
) вы всегда получите121
результат.источник