Siempre estaba inseguro, ¿qué significa la palabra clave restringir en C ++?
¿Significa que los dos o más punteros dados a la función no se superponen? ¿Qué más significa?
c++
restrict-qualifier
Estera
fuente
fuente
restrict
es una palabra clave c99. Sí, Rpbert S. Barnes, sé que la mayoría de los compiladores son compatibles__restrict__
. Notará que cualquier cosa con guiones bajos dobles es, por definición, específica de implementación y, por lo tanto, NO C ++ , sino una versión específica del compilador.#warning
directiva común o las macros de firma de funciones (__PRETTY_FUNCTION__
en GCC,__FUNCSIG__
en MSVC, etc.).restrict
no se considera una palabra clave de C ++ (consulte en.cppreference.com/w/cpp/keyword ), y de hecho, la única menciónrestrict
en el estándar C ++ 11 (consulte open-std.org/jtc1/sc22/wg21 /docs/papers/2012/n3337.pdf , una copia del FDIS con pequeños cambios editoriales, §17.2 [library.c], PDF página 413) establece que:restrict
se debe omitir (excluir, excluir) de las firmas y semánticas de la función de biblioteca estándar de C cuando esas funciones se incluyen en la biblioteca estándar de C ++. O en otras palabras, dije el hecho que dice que si la firma de una función de biblioteca estándar de C contienerestrict
C, larestrict
palabra clave debe eliminarse de la firma del equivalente de C ++.Respuestas:
En su artículo, Memory Optimization , Christer Ericson dice que mientras
restrict
todavía no forma parte del estándar C ++, que es compatible con muchos compiladores y recomienda su uso cuando esté disponible:En los compiladores de C ++ que lo admiten, probablemente debería comportarse igual que en C.
Vea esta publicación SO para más detalles: Uso realista de la palabra clave 'restringir' C99?
Tómese media hora para leer el papel de Ericson, es interesante y vale la pena.
Editar
También descubrí que el compilador AIX C / C ++ de
__restrict__
IBM admite la palabra clave .g ++ también parece admitir esto ya que el siguiente programa se compila limpiamente en g ++:
También encontré un buen artículo sobre el uso de
restrict
:Desmitificando la palabra clave restringida
Edit2
Me encontré con un artículo que analiza específicamente el uso de restrict en los programas de C ++:
Load-hit-stores y la palabra clave __restrict
Además, Microsoft Visual C ++ también admite la
__restrict
palabra clave .fuente
#ifndef __GNUC__
#define __restrict__ /* no-op */
o similar. Y definirlo a__restrict
si_MSC_VER
está definido.Como otros dijeron, si no significa nada a partir de C ++ 14 , entonces consideremos la
__restrict__
extensión GCC que hace lo mismo que el C99restrict
.C99
restrict
dice que dos punteros no pueden apuntar a regiones de memoria superpuestas. El uso más común es para argumentos de función.Esto restringe cómo se puede llamar a la función, pero permite más optimizaciones de compilación.
Si la persona que llama no sigue el
restrict
contrato, comportamiento indefinido.El C99 N1256 borrador 6.7.3 / 7 "Calificadores de tipo" dice:
y 6.7.3.1 "Definición formal de restricción" da los detalles sangrientos.
Una posible optimización
El ejemplo de Wikipedia es muy esclarecedor.
Muestra claramente cómo, ya que permite guardar una instrucción de ensamblaje .
Sin restricción:
Pseudo ensamblaje:
Con restringir:
Pseudo ensamblaje:
¿GCC realmente lo hace?
g++
4.8 Linux x86-64:Con
-O0
, son lo mismo.Con
-O3
:Para los no iniciados, la convención de convocatoria es:
rdi
= primer parámetrorsi
= segundo parámetrordx
= tercer parámetroLa salida de GCC fue incluso más clara que el artículo wiki: 4 instrucciones vs 3 instrucciones.
Matrices
Hasta ahora, tenemos ahorros en una sola instrucción, pero si el puntero representa las matrices que se van a recorrer, un caso de uso común, entonces se podrían guardar un montón de instrucciones, como lo mencionaron supercat y michael .
Considere por ejemplo:
Debido a que
restrict
un compilador inteligente (o humano), podría optimizar eso para:¿Qué es potencialmente mucho más eficiente, ya que puede ser ensamblado optimizado en una implementación decente de libc (como glibc) ¿Es mejor usar std :: memcpy () o std :: copy () en términos de rendimiento? , posiblemente con instrucciones SIMD .
Sin, restringir, esta optimización no podría hacerse, por ejemplo, considere:
Entonces la
for
versión hace:mientras que la
memset
versión hace:¿GCC realmente lo hace?
GCC 5.2.1.Linux x86-64 Ubuntu 15.10:
Con
-O0
ambos son lo mismo.Con
-O3
:con restricción:
Dos
memset
llamadas como se esperaba.sin restricción: no hay llamadas stdlib, solo un desenrollamiento de bucle ancho de 16 iteraciones que no pretendo reproducir aquí :-)
No he tenido la paciencia para compararlos, pero creo que la versión restringida será más rápida.
Regla de alias estricta
La
restrict
palabra clave solo afecta a punteros de tipos compatibles (por ejemplo, dosint*
) porque las estrictas reglas de alias dicen que el alias de tipos incompatibles es un comportamiento indefinido por defecto, por lo que los compiladores pueden asumir que no sucede y optimizar.Ver: ¿Cuál es la estricta regla de alias?
¿Funciona para referencias?
De acuerdo con los documentos de GCC, sí lo hace: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html con sintaxis:
Incluso hay una versión para las
this
funciones miembro:fuente
-fno-strict-aliasing
, entonces norestrict
debería haber diferencia entre punteros del mismo tipo o tipos diferentes, no? (Me refiero a "La palabra clave restringir solo afecta a punteros de tipos compatibles")restrict
significa algo en C ++. Si llama a una función de biblioteca C conrestrict
parámetros de un programa C ++, debe obedecer las implicaciones de eso. Básicamente, sirestrict
se usa en una API de biblioteca C significa algo para cualquiera que lo llame desde cualquier lenguaje, incluido el FFI dinámico de Lisp.Nada. Fue agregado al estándar C99.
fuente
restrict
como una palabra clave. Por lo tanto, mi respuesta es correcta. Lo que describe es un comportamiento específico de implementación y algo en lo que realmente no debe confiar.Esta es la propuesta original para agregar esta palabra clave. Sin embargo, como se señaló puntualmente, esta es una característica de C99 ; No tiene nada que ver con C ++.
fuente
__restrict__
palabra clave que es idéntica por lo que puedo decir.restrict
. El comportamiento del programa C ++ se vuelve indefinido si viola las restricciones implicadas porrestrict
.restrict
palabra clave. Por supuesto, si pasa punteros con alias a una función C que los declara restringidos (lo que puede hacer desde C ++ o C), entonces no está definida, pero eso depende de usted.restrict
. El comportamiento del programa C ++ se vuelve indefinido si viola las restricciones implicadas por restrict. Pero esto en realidad no tiene nada que ver con C ++, porque está "en ti".No existe tal palabra clave en C ++. La lista de palabras clave de C ++ se puede encontrar en la sección 2.11 / 1 del estándar de lenguaje C ++.
restrict
es una palabra clave en la versión C99 del lenguaje C y no en C ++.fuente
__restrict__
palabra clave que es idéntica por lo que puedo decir.Dado que los archivos de encabezado de algunas bibliotecas C usan la palabra clave, el lenguaje C ++ tendrá que hacer algo al respecto ... como mínimo, ignorando la palabra clave, por lo que no tenemos que #definir la palabra clave en una macro en blanco para suprimir la palabra clave .
fuente
extern C
declaración, o se descarta silenciosamente, como es el caso con el compilador AIX C / C ++, que en su lugar maneja la__rerstrict__
palabra clave. Esa palabra clave también es compatible con gcc para que el código compile lo mismo con g ++.