El tipo de problema Chandler estaba hablando puede ser fácilmente ilustrado con un sistema simplificado strcpy
:
char *stpcpy (char * dest, const char * src);
Al escribir una implementación de esto, puede suponer que la memoria apuntada por dest
está completamente separada de la memoria apuntada por src
. El compilador) puede querer optimizarlo leyendo un bloque de caracteres de la cadena apuntada por src
y escribiendo todos a la vez en dest
. Pero si dest
apunta a un byte delante de src
, el comportamiento de esto diferiría de una simple copia de carácter por carácter.
Aquí el problema es que el aliasing src
puede crear un alias dest
, y el código generado debe ser menos eficiente de lo que podría ser si src
no se le permitió alias dest
.
El verdadero strcpy
utiliza una palabra clave adicional, Restrict (que es technically only part of C, not C++, que le dice al compilador que asumir que src
y dest
no se solapan, y esto permite que el compilador generar código mucho más eficiente.
He aquí un ejemplo aún más simple en el que podemos ver una gran diferencia en la asamblea:
void my_function_1(int* a, int* b, int* c) {
if (*a) *b = *a;
if (*a) *c = *a;
}
void my_function_2(int* __restrict a, int* __restrict b, int* __restrict c) {
if (*a) *b = *a;
if (*a) *c = *a;
}
suponer que esto es una simplificación de una función donde en realidad tiene sentido usar dos declaraciones if en lugar de solo if (*a) { *b=*a; *c=*a; }
, pero la intención es la misma.
Podemos suponer al escribir esto que a != b
porque hay alguna razón por la que no tendría sentido que my_function
se use así.Sin embargo, el compilador no puede asumir que, y lo hace de una tienda de b
y una re-carga de a
de la memoria antes de ejecutar la segunda línea, para cubrir el caso en que b == a
:
0000000000400550 <my_function_1>:
400550: 8b 07 mov (%rdi),%eax
400552: 85 c0 test %eax,%eax <= if (*a)
400554: 74 0a je 400560 <my_function_1+0x10>
400556: 89 06 mov %eax,(%rsi)
400558: 8b 07 mov (%rdi),%eax
40055a: 85 c0 test %eax,%eax <= if (*a)
40055c: 74 02 je 400560 <my_function_1+0x10>
40055e: 89 02 mov %eax,(%rdx)
400560: f3 c3 repz retq
Si eliminamos potencial de aliasing añadiendo __restrict
, el compilador genera código más corto y más rápido:
0000000000400570 <my_function_2>:
400570: 8b 07 mov (%rdi),%eax
400572: 85 c0 test %eax,%eax
400574: 74 04 je 40057a <_Z9my_function_2PiS_S_+0xa>
400576: 89 06 mov %eax,(%rsi)
400578: 89 02 mov %eax,(%rdx)
40057a: f3 c3 repz retq
¿Por qué no le preguntas a Chandler Carruth? –
posible duplicado de [alias estricto] (http://stackoverflow.com/questions/754929/strict-aliasing) –
Intente ver [this] (http://cslibrary.stanford.edu/104/). En realidad es bastante bueno.El aliasing es cuando se toma el puntero de un objeto en lugar del propio objeto, como él explica. –