Cuándo usar restringir y cuándo no
pointers c99 (3)
Tengo un entendimiento general de restrict
pero espero aclarar algunos puntos finos. Tengo una función que lee una cadena terminada en nulo de un búfer y escribe una versión codificada de URL en otro búfer. La función tiene esta firma (actualmente sin restrict
):
char const *StringUrlEncode(char const *unencoded,
char *encoded,
char *encodedEnd);
unencoded
es mi cadena de origen terminada en nulo. El búfer de destino está representado por encoded
y encodedEnd
, donde los puntos encoded
al primer char
en el búfer y encodedEnd
apunta al primer carácter después del búfer, es decir, la función escribirá los caracteres hasta la ubicación señalada por encodedEnd
pero no - este es su par básico de iteradores de begin
/ end
si está familiarizado con las convenciones STL de C ++.
Si agrego restrict
a esta función, solo debería aplicarse a los dos primeros parámetros:
char const *StringUrlEncode(char const *restrict unencoded,
char *restrict encoded,
char *encodedEnd);
¿O hay algún beneficio que no entiendo al agregarlo a los tres parámetros?
Puedo ver que hacer que los buffers de entrada y salida sean restrict
ayuda al compilador a saber que no se superponen. Pero como el último parámetro, encodedEnd
, solo se usa para marcar el final del búfer de salida, creo que restrict
no sería realmente una ayuda para el compilador aquí (aunque supongo que no estaría mal, aparte de agregar Ruido innecesario a la declaración de función).
Creo que tienes razón en que no dolería. Su puntero de bucle (llámelo p) será igual a encodedEnd al final del bucle. Pero no es necesario acceder a nada después del bucle (desde p o encodedEnd), por lo que no debería ser un problema. Tampoco creo que ayude, porque nunca se escribe ni se lee nada de encodedEnd, así que no hay nada que optimizar.
Pero estoy de acuerdo con que tener las dos primeras restricciones realmente debería ayudar.
En este caso particular, no hará una diferencia si encodedEnd está restringido o no; le prometiste al compilador que nadie alias sin codificar ni codificar , por lo que las lecturas y escrituras no interferirán entre sí.
La verdadera razón por la que la restricción es importante en este caso es que sin ella el compilador no puede saber que las escrituras codificadas no afectarán las lecturas no codificadas . Por ejemplo, si
encoded == unencoded+1
entonces cada escritura en codificada afectaría a cada lectura posterior de no codificada , por lo que el compilador no puede programar la carga hasta que la escritura haya finalizado. restringir promete al compilador que los dos punteros no afectan a la misma memoria, por lo que puede programar las cargas con la suficiente antelación para evitar bloqueos en la tubería.
Prueba el artículo de Mike Acton here . Restringir es aterrador debido a las implicaciones en el rendimiento de no usarlo y las consecuencias de usarlo incorrectamente.
En su caso, parece que podría aplicar de forma segura el restringir a los tres punteros como ninguno alias en la misma área de memoria. Sin embargo, habrá poco o ningún beneficio de rendimiento al usarlo en el tercer puntero.