Articulo de referencia

restringir

En el lenguaje de programación C , `<type> restrict ` es un calificador de tipo que se puede aplicar a un puntero para indicar al compilador que, durante la vida útil de dicho p...

En el lenguaje de programación C , `<type> restrict` es un calificador de tipo que se puede aplicar a un puntero para indicar al compilador que, durante la vida útil de dicho puntero, ningún otro puntero accederá al mismo objeto. Esto limita los efectos del aliasing de punteros , lo que permite al compilador realizar optimizaciones (como la vectorización ) que de otro modo no serían posibles. Se produce un comportamiento indefinido si no se respeta la declaración de intención y se accede al objeto mediante un puntero independiente.

La restrictpalabra clave fue introducida por el estándar C99 . A pesar de que C++ admite la mayoría de las características de C , restrictno está incluida en el estándar C++.

Mejoramiento

Si el compilador sabe que solo hay un puntero a un bloque de memoria, puede producir un código mejor optimizado. Por ejemplo, en una función que updatePointers()suma un valor xa sus dos argumentos a:b

void updatePointers ( size_t * a , size_t * b , size_t * x ) { * a += * x ; * b += * x ; }

En el código anterior, los punteros a, b, y xpodrían referirse a la misma ubicación de memoria , por lo que el compilador podría generar un código menos óptimo:

; Máquina RISC hipotética. ldr r12 , [ x ] ; Carga la memoria en x a r12. ldr r3 , [ a ] ​​; Carga la memoria en a a r3. add r3 , r3 , r12 ; Realiza la suma: r3 = r3 + r12. str r3 , [ a ] ​​; Almacena r3 en la ubicación de memoria a, actualizando el valor. ldr r3 , [ b ] ; 'load' puede tener que esperar hasta que 'store' anterior se complete. ldr r12 , [ x ] ; Hay que cargar una segunda vez para asegurar la consistencia. add r3 , r3 , r12 str r3 , [ b ]

Sin embargo, si restrictse utiliza la palabra clave y la función anterior se declara como

void updatePointers ( size_t * restrict a , size_t * restrict b , size_t * restrict x ) { * a += * x ; * b += * x ; }

Entonces, el compilador puede asumir que a, b, y xapuntan a ubicaciones diferentes, y que actualizar la ubicación de memoria a la que apunta un puntero no afectará a las ubicaciones de memoria a las que apuntan los demás punteros. El programador, no el compilador, es responsable de garantizar que los punteros no apunten a ubicaciones idénticas. El compilador puede, por ejemplo, reorganizar el código, cargando primero todas las ubicaciones de memoria y luego realizando las operaciones antes de guardar los resultados en la memoria.

ldr r12 , [ x ] ; Nótese que x ahora solo se carga una vez. ldr r3 , [ a ] ​​; Además, todas las 'cargas' al principio ... ldr r4 , [ b ] add r3 , r3 , r12 add r4 , r4 , r12 str r3 , [ a ] ​​; ... todas las 'almacenamientos' al final. str r4 , [ b ]

El código ensamblador anterior es más corto porque xse carga solo una vez. Sin xrestricciones, es posible crear aun alias con él. Esto provocaría xun cambio en la primera suma, cuando ase actualiza, y por lo tanto, sería necesario recargarlo. El código ensamblador anterior también es más rápido, ya que el compilador puede reorganizar el código con mayor libertad. En la segunda versión del ejemplo anterior, storetodas las operaciones se realizan después de las loadoperaciones, lo que garantiza que el procesador no tenga que bloquearse en medio del código para esperar a que las storeoperaciones se completen. Este reordenamiento es posible porque los punteros ay bse marcaron con restrict, lo que garantiza que el usuario no llame a la función con estos punteros en alias, esperando xque se sume dos veces al entero al que ambos hacen referencia.

Tenga en cuenta que el código generado real puede tener comportamientos diferentes, dependiendo de cómo el compilador utilice la información adicional. El beneficio del miniejemplo anterior puede ser mínimo, y en casos reales, los bucles grandes que realizan un acceso intensivo a la memoria suelen ser los que realmente se benefician de la restricción.

Como se mencionó anteriormente, el comportamiento del código incorrecto es indefinido . El compilador solo garantiza que el código generado funcione correctamente si se ajusta a la declaración de intenciones, y las optimizaciones que habilita probablemente provoquen un comportamiento incorrecto cuando los punteros sean alias. En algunos casos, los compiladores pueden detectar y advertir sobre la existencia de alias en los punteros, pero no están obligados a hacerlo.

Compatibilidad con compiladores de C++

C++ no tiene soporte estándar para restrict, pero muchos compiladores tienen equivalentes que suelen funcionar tanto en C++ como en C, como los de GCC y Clang__restrict__ , y el de Visual C++ . __declspec(restrict)Además, __restrictes compatible con esos tres compiladores. La interpretación exacta de estas palabras clave alternativas varía según el compilador:

  • En compiladores de estilo Unix como GCC y Clang, __restricty __restrict__significan exactamente lo mismo que su contraparte en C. Las extensiones incluyen permitir que se apliquen a tipos de referencia y this. [ 1 ]
  • En Visual C++, se proporcionan varios calificadores sin alias:
    1. __declspec(restrict)Se aplica a la declaración de la función e indica que el puntero devuelto no tiene alias.
    2. __restrictse utiliza en el mismo lugar que restrict, pero la sugerencia sin alias no se propaga como en restrict. También se extiende para tipos de unión .

restrictsigue siendo utilizable en un contexto de ( enlace C ).extern"C"

Advertencias del compilador

Para ayudar a prevenir código incorrecto, algunos compiladores y otras herramientas intentan detectar cuándo se han pasado argumentos superpuestos a funciones con parámetros marcados con restrict. [ 2 ] El estándar de codificación CERT C considera que el mal uso de restricty las funciones de biblioteca marcadas con él (EXP43-C) es una fuente probable de errores de software.

Referencias

  1. "Punteros restringidos" . Uso de la colección de compiladores GNU (GCC) .
  2. "Opciones de advertencia: -Wrestrict" . GCC . Consultado el 19 de noviembre de 2019 .
  • "ISO/IEC 9899: Borrador del Comité TC2" (PDF) . ISO . 6 de mayo de 2005. págs. 108–112 . Consultado el 22 de diciembre de 2008 . 
  • Desmitificando la palabra clave Restrict : explicación y ejemplos de uso
  • Walls, Douglas. "Cómo usar el calificador restrict en C" . Oracle™ . Consultado el 21 de noviembre de 2012 .
  • Punteros restringidos en C : la razón de ser original de la definición