Quiero escribir una función que introducir una serie de datos y salida de otra serie de datos utilizando punteros.
Me pregunto cuál es el resultado si ambos src
y dst
en punta a la misma dirección, porque sé compilador puede optimizar para la const. ¿Es indefinido comportamiento? (I tagged tanto C como C ++, porque no estoy seguro de si la respuesta puede diferir entre ellos, y yo quiero saber de ambos).
void f(const char *src, char *dst) {
dst[2] = src[0];
dst[1] = src[1];
dst[0] = src[2];
}
int main() {
char s[] = "123";
f(s,s);
printf("%s\n", s);
return 0;
}
Además de la pregunta anterior, es este bien definido si elimino el const
en el código original?
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, es un compilador no permitió asumir que sólo porque un parámetro es una const T* ptr
, la memoria a la que apunta ptr
no será cambiado por otro puntero. Los punteros ni siquiera tienen que ser iguales. El const
es una obligación, no una garantía - la obligación por usted (= la función) de no hacer cambios a través de ese puntero.
Con el fin de tener en realidad esa garantía, es necesario marcar el puntero con la restrict
palabra clave. Por lo tanto, si se 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()
sólo tiene que leer 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
Ver esto en vivo GodBolt.
restrict
sólo es una palabra clave en C (desde C99); por desgracia, no ha sido introducida en C ++ hasta el momento (para los pobres razón por la que más complicado para introducirlo en C ++). Muchos compiladores un poco de apoyo que, sin embargo, como __restrict
.
En pocas palabras: El compilador debe apoyar su caso "esotérica" se utiliza para compilar f()
, y no tendrá ningún problema con él.
Ver este post con respecto a los casos de uso para restrict
.