Si bien es cierto que el comportamiento está bien definido - es no cierto que los compiladores pueden "optimizar para la const" en el sentido de que usted se refiere.
Es decir, un compilador no puede asumir que solo porque un parámetro sea a const T* ptr
, la memoria a la que apunta ptr
no se cambiará a través de otro puntero. Los punteros ni siquiera tienen que ser iguales. El const
es una obligación, no una garantía, una obligación suya (= la función) de no realizar cambios a través de ese puntero.
Para tener esa garantía, debe marcar el puntero con la restrict
palabra clave. Por lo tanto, si compila estas dos funciones:
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;
}
la foo()
función debe leer dos veces x
, mientras que bar()
solo necesita leerla una vez:
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
Mira esto en vivo GodBolt.
restrict
es solo una palabra clave en C (desde C99); desafortunadamente, no se ha introducido en C ++ hasta ahora (por la mala razón de que es más complicado introducirlo en C ++). Sin embargo, muchos compiladores sí lo admiten __restrict
.
En pocas palabras: el compilador debe admitir su caso de uso "esotérico" al compilar f()
, y no tendrá ningún problema.
Vea esta publicación sobre casos de uso para restrict
.
const
no es "una obligación suya (= la función) no hacer cambios a través de ese puntero". El estándar C permite que la función se elimineconst
mediante una conversión y luego se modifique el objeto a través del resultado. Esencialmente,const
es solo una asesoría y una conveniencia para el programador para ayudar a evitar modificar un objeto sin darse cuenta.memcpy
ystrcpy
se declaran conrestrict
argumentos, mientrasmemmove
que no lo es: solo este último permite la superposición entre los bloques de memoria.Esto está bien definido (en C ++, ya no estoy seguro en C), con y sin el
const
calificador.Lo primero que debe buscar es la estricta regla de alias 1 . Si
src
ydst
apunta al mismo objeto:char*
ychar const*
no son compatibleschar*
ychar const*
son similaresCon respecto al
const
calificador, podría argumentar que, dado que cuandodst == src
su función modifica efectivamente a quésrc
puntos,src
no debería calificarse comoconst
. Así no es comoconst
funciona. Deben considerarse dos casos:const
, como enchar const data[42];
, modificarlo (directa o indirectamente) conduce a Comportamiento indefinido.const
se define una referencia o puntero a un objeto, como enchar const* pdata = data;
, se puede modificar el objeto subyacente siempre que no se haya definido comoconst
2 (ver 1.). Entonces lo siguiente está bien definido:1) ¿Cuál es la estricta regla de alias?
2) ¿Es
const_cast
seguro?fuente
char*
ychar const*
no son compatibles_Generic((char *) 0, const char *: 1, default: 0))
evalúa a cero.const
se define una referencia o un puntero a un objeto" es incorrecta. Quiere decir que cuando se define una referencia o un puntero a un tipoconst
calificado , eso no significa que el objeto al que está configurado para apuntar no puede modificarse (por varios medios). (Si el puntero apunta a un objeto, eso significa que el objeto es por definición, por lo que el comportamiento de tratar de modificarlo no está definido.)const
const
language-lawyer
. La exactitud es un valor que aprecio, pero también soy consciente de que viene con más complejidad. Aquí, decidí ir por simplicidad y oraciones fáciles de entender, porque creo que esto es lo que quería OP OP. Si piensa lo contrario, responda, estaré entre los primeros en votarlo. De todos modos, gracias por tu comentario.Esto está bien definido en C. Las reglas de alias estrictas no se aplican con el
char
tipo, ni con dos punteros del mismo tipo.No estoy seguro de lo que quieres decir con "optimizar para
const
". Mi compilador (GCC 8.3.0 x86-64) genera exactamente el mismo código para ambos casos. Si agrega elrestrict
especificador a los punteros, el código generado es ligeramente mejor, pero eso no funcionará para su caso, ya que los punteros son los mismos.(C11 §6.5 7)
En este caso (sin
restrict
), siempre obtendrá121
como resultado.fuente