Los bloques son una extensión no estándar agregada por Apple Inc. a las implementaciones de Clang de los lenguajes de programación C , C ++ y Objective-C que usa una sintaxis similar a una expresión lambda para crear cierres dentro de estos lenguajes. Los bloques son compatibles con programas desarrollados para Mac OS X 10.6+ e iOS 4.0+, [1] aunque los tiempos de ejecución de terceros permiten su uso en Mac OS X 10.5 e iOS 2.2+ [2] y sistemas que no sean de Apple.
Apple diseñó bloques con el objetivo explícito de facilitar la escritura de programas para la arquitectura de subprocesos de Grand Central Dispatch , [3] [4] aunque es independiente de esa arquitectura y se puede usar de la misma manera que los cierres en otros lenguajes. Apple ha implementado bloques tanto en su propia rama de GNU Compiler Collection [1] como en el front-end del compilador Clang LLVM . El soporte de la biblioteca de tiempo de ejecución de idiomas para bloques también está disponible como parte del proyecto LLVM. El grupo Khronos usa la sintaxis de bloques para poner en cola los núcleos desde dentro de los núcleos a partir de la versión 2.0 de OpenCL . [5]
Al igual que las definiciones de funciones, los bloques pueden tomar argumentos y declarar sus propias variables internamente. A diferencia de las definiciones de funciones de C ordinarias, su valor puede capturar el estado de su contexto circundante. Una definición de bloque produce un valor opaco que contiene tanto una referencia al código dentro del bloque como una instantánea del estado actual de las variables de la pila local en el momento de su definición. El bloque puede invocarse posteriormente de la misma manera que un puntero de función. El bloque puede asignarse a variables, pasarse a funciones y tratarse como un puntero de función normal, aunque el programador de la aplicación (o la API) debe marcar el bloque con un operador especial (Block_copy) si se va a utilizar fuera del alcance en que se definió.
Dado un valor de bloque, el código dentro del bloque se puede ejecutar en cualquier momento posterior llamándolo, usando la misma sintaxis que se usaría para llamar a una función.
Ejemplos de
Un ejemplo simple que captura el estado mutable en el ámbito circundante es un iterador de rango entero : [6]
/ * blocks-test.c * / #include #include / * Tipo de bloque que no toma nada devolviendo un int * / typedef int ( ^ IntBlock ) ();IntBlock MakeCounter ( int inicio , int incremento ) { __block int i = start ;return Block_copy ( ^ ( void ) { int ret = i ; i + = incremento ; return ret ; });}int main ( void ) { IntBlock mycounter = MakeCounter ( 5 , 2 ); printf ( "Primera llamada:% d \ n " , mycounter ()); printf ( "Segunda llamada:% d \ n " , mycounter ()); printf ( "Tercera llamada:% d \ n " , mycounter ());/ * porque fue copiado, también debe ser liberado * / Block_release ( mycounter );return 0 ; }
Compilar y ejecutar
$ clang -fblocks blocks-test.c # Mac OS X $ ./a.out Primera llamada: 5 Segunda llamada: 7 Tercera llamada: 9
El tiempo de ejecución de los bloques no forma parte de la (s) biblioteca (s) de C vinculadas por defecto en algunos sistemas. Si este es el caso, es necesario vincular explícitamente a esta biblioteca:
$ clang -fblocks blocks-test.c -lBlocksRuntime # Linux
El tiempo de ejecución es parte del tiempo de ejecución de clang, pero a veces no se instala con el paquete clang. Hay disponible un tiempo de ejecución independiente extraído de compiler-rt. [7]
Relación con las funciones anidadas de GCC
Los bloques tienen un parecido superficial con la extensión de C de GCC para admitir funciones anidadas de ámbito léxico . [8] Sin embargo, las funciones anidadas de GCC, a diferencia de los bloques, no deben llamarse después de que el ámbito contenedor haya salido, ya que eso daría como resultado un comportamiento indefinido .
Las funciones anidadas de estilo GCC actualmente utilizan la creación dinámica de procesadores ejecutables en la mayoría de las arquitecturas al tomar la dirección de la función anidada. En la mayoría de las arquitecturas (incluido X86), estos procesadores se crean en la pila, lo que requiere marcar la pila como ejecutable. Las pilas ejecutables generalmente se consideran un potencial agujero de seguridad. Los bloques no requieren el uso de procesadores ejecutables, por lo que no comparten esta debilidad. Por otro lado, los bloques introducen un tipo completamente nuevo para el puntero, mientras que los punteros a funciones anidadas en GCC son punteros a funciones regulares y se pueden usar directamente con el código existente.
Ver también
- Cierre (informática)
- Alcance léxico
- Lambda (programación)
- Pila de espaguetis
- Thunk (programación funcional)
- XNU
- C ++ 11 (incluye "expresiones lambda")
Referencias
- ^ a b "Temas de programación de bloques" . Desarrollador de Apple . Apple . Consultado el 8 de marzo de 2011 .
- ^ https://code.google.com/p/plblocks/
- ^ "Grand Central Dispatch" (PDF) (resumen de tecnología). Manzana . 2009-09-03. Archivado desde el original (PDF) el 20 de septiembre de 2009 . Consultado el 9 de junio de 2009 .
- ^ Siracusa, John (1 de septiembre de 2009). "Mac OS X 10.6 Snow Leopard: la revisión de Ars Technica: bloques" . Ars Technica .
- ^ Munshi, Aaftab, ed. (13 de julio de 2013). "La especificación OpenCL C. Versión 2.0. Revisión del documento 11" (PDF) . Grupo de trabajo Khronos OpenCL. pag. 173. Archivado desde el original (PDF) el 5 de noviembre de 2013 . Consultado el 23 de julio de 2013 .
- ^ Bengtsson, Joachim. "Programación con bloques C en dispositivos Apple" . Archivado desde el original el 15 de noviembre de 2017 . Consultado el 17 de septiembre de 2009 .
- ^ "mackyle / blocksruntime: tiempo de ejecución de bloques autónomos" . Consultado el 15 de enero de 2020 .
- ^ "Funciones anidadas: uso de la colección de compiladores GNU (GCC)" .
enlaces externos
- "Extensiones de lenguaje Clang: bloques" . Proyecto LLVM . Consultado el 20 de enero de 2013 .
- " " compiler-rt "Biblioteca en tiempo de ejecución" . Proyecto LLVM . Consultado el 20 de enero de 2013 .