| .. include:: ../disclaimer-sp.rst |
| |
| :Original: :ref:`Documentation/process/coding-style.rst <submittingpatches>` |
| :Translator: Carlos Bilbao <carlos.bilbao.osdev@gmail.com> |
| |
| .. _sp_codingstyle: |
| |
| Estilo en el código del kernel Linux |
| ===================================== |
| |
| Este es un breve documento que describe el estilo preferido en el código |
| del kernel Linux. El estilo de código es muy personal y no **forzaré** mi |
| puntos de vista sobre nadie, pero esto vale para todo lo que tengo que |
| mantener, y preferiría que para la mayoría de otras cosas también. Por |
| favor, por lo menos considere los argumentos expuestos aquí. |
| |
| En primer lugar, sugeriría imprimir una copia de los estándares de código |
| GNU, y NO leerlo. Quémelos, es un gran gesto simbólico. |
| |
| De todos modos, aquí va: |
| |
| |
| 1) Sangría |
| ----------- |
| |
| Las tabulaciones tienen 8 caracteres y, por lo tanto, las sangrías también |
| tienen 8 caracteres. Hay movimientos heréticos que intentan hacer sangría |
| de 4 (¡o incluso 2!) caracteres de longitud, y eso es similar a tratar de |
| definir el valor de PI como 3. |
| |
| Justificación: La idea detrás de la sangría es definir claramente dónde |
| comienza y termina un bloque de control. Especialmente, cuando ha estado |
| buscando en su pantalla durante 20 horas seguidas, le resultará mucho más |
| fácil ver cómo funciona la sangría si tiene sangrías grandes. |
| |
| Bueno, algunas personas dirán que tener sangrías de 8 caracteres hace que |
| el código se mueva demasiado a la derecha y dificulta la lectura en una |
| pantalla de terminal de 80 caracteres. La respuesta a eso es que si |
| necesita más de 3 niveles de sangría, está en apuros de todos modos y |
| debería arreglar su programa. |
| |
| En resumen, las sangrías de 8 caracteres facilitan la lectura y tienen la |
| ventaja añadida de advertirle cuando está anidando sus funciones demasiado |
| profundo. Preste atención a esa advertencia. |
| |
| La forma preferida de facilitar múltiples niveles de sangría en una |
| declaración de switch es para alinear el ``switch`` y sus etiquetas |
| ``case`` subordinadas en la misma columna, en lugar de hacer ``doble |
| sangría`` (``double-indenting``) en etiquetas ``case``. Por ejemplo: |
| |
| .. code-block:: c |
| |
| switch (suffix) { |
| case 'G': |
| case 'g': |
| mem <<= 30; |
| break; |
| case 'M': |
| case 'm': |
| mem <<= 20; |
| break; |
| case 'K': |
| case 'k': |
| mem <<= 10; |
| fallthrough; |
| default: |
| break; |
| } |
| |
| No ponga varias declaraciones en una sola línea a menos que tenga algo que |
| ocultar: |
| |
| .. code-block:: c |
| |
| if (condición) haz_esto; |
| haz_otra_cosa; |
| |
| No use comas para evitar el uso de llaves: |
| |
| .. code-block:: c |
| |
| if (condición) |
| haz_esto(), haz_eso(); |
| |
| Siempre use llaves para múltiples declaraciones: |
| |
| .. code-block:: c |
| |
| if (condición) { |
| haz_esto(); |
| haz_eso(); |
| } |
| |
| Tampoco ponga varias asignaciones en una sola línea. El estilo de código |
| del kernel es súper simple. Evite las expresiones engañosas. |
| |
| |
| Aparte de los comentarios, la documentación y excepto en Kconfig, los |
| espacios nunca se utilizan para la sangría, y el ejemplo anterior se rompe |
| deliberadamente. |
| |
| Consiga un editor decente y no deje espacios en blanco al final de las |
| líneas. |
| |
| 2) Rompiendo líneas y strings largos |
| ------------------------------------ |
| |
| El estilo de código tiene todo que ver con la legibilidad y la |
| mantenibilidad usando herramientas disponibles comúnmente. |
| |
| El límite preferido en la longitud de una sola línea es de 80 columnas. |
| |
| Las declaraciones de más de 80 columnas deben dividirse en partes, a menos |
| que exceder las 80 columnas aumente significativamente la legibilidad y no |
| oculte información. |
| |
| Los descendientes siempre son sustancialmente más cortos que el padre y |
| se colocan sustancialmente a la derecha. Un estilo muy usado es alinear |
| descendientes a un paréntesis de función abierto. |
| |
| Estas mismas reglas se aplican a los encabezados de funciones con una larga |
| lista de argumentos. |
| |
| Sin embargo, nunca rompa los strings visibles para el usuario, como los |
| mensajes printk, porque eso rompe la capacidad de grep a estos. |
| |
| |
| 3) Colocación de llaves y espacios |
| ---------------------------------- |
| |
| El otro problema que siempre surge en el estilo C es la colocación de |
| llaves. A diferencia del tamaño de la sangría, existen pocas razones |
| técnicas para elegir una estrategia de ubicación sobre la otra, pero la |
| forma preferida, como mostraron los profetas Kernighan y Ritchie, es poner |
| la llave de apertura en la línea, y colocar la llave de cierre primero, |
| así: |
| |
| .. code-block:: c |
| |
| if (x es verdad) { |
| hacemos y |
| } |
| |
| Esto se aplica a todos los bloques de declaraciones que no son funciones |
| (if, switch, for, while, do). Por ejemplo: |
| |
| .. code-block:: c |
| |
| switch (action) { |
| case KOBJ_ADD: |
| return "add"; |
| case KOBJ_REMOVE: |
| return "remove"; |
| case KOBJ_CHANGE: |
| return "change"; |
| default: |
| return NULL; |
| } |
| |
| Sin embargo, hay un caso especial, a saber, las funciones: tienen la llave |
| de apertura al comienzo de la siguiente línea, así: |
| |
| .. code-block:: c |
| |
| int funcion(int x) |
| { |
| cuerpo de la función |
| } |
| |
| Gente hereje de todo el mundo ha afirmado que esta inconsistencia es... |
| bueno... inconsistente, pero todas las personas sensatas saben que |
| (a) K&R tienen **razón** y (b) K&R tienen razón. Además, las funciones son |
| especiales de todos modos (no puede anidarlas en C). |
| |
| Tenga en cuenta que la llave de cierre está vacía en su línea propia, |
| **excepto** en los casos en que es seguida por una continuación de la misma |
| declaración, es decir, un ``while`` en una sentencia do o un ``else`` en |
| una sentencia if, como en: |
| |
| .. code-block:: c |
| |
| do { |
| cuerpo del bucle do |
| } while (condition); |
| |
| y |
| |
| .. code-block:: c |
| |
| if (x == y) { |
| .. |
| } else if (x > y) { |
| ... |
| } else { |
| .... |
| } |
| |
| Justificación: K&R. |
| |
| Además, tenga en cuenta que esta colocación de llaves también minimiza el |
| número de líneas vacías (o casi vacías), sin pérdida de legibilidad. Así, |
| como el suministro de nuevas líneas en su pantalla no es un recurso |
| renovable (piense en pantallas de terminal de 25 líneas), tienes más líneas |
| vacías para poner comentarios. |
| |
| No use llaves innecesariamente donde una sola declaración sea suficiente. |
| |
| .. code-block:: c |
| |
| if (condition) |
| accion(); |
| |
| y |
| |
| .. code-block:: none |
| |
| if (condición) |
| haz_esto(); |
| else |
| haz_eso(); |
| |
| Esto no aplica si solo una rama de una declaración condicional es una sola |
| declaración; en este último caso utilice llaves en ambas ramas: |
| |
| .. code-block:: c |
| |
| if (condición) { |
| haz_esto(); |
| haz_eso(); |
| } else { |
| en_otro_caso(); |
| } |
| |
| Además, use llaves cuando un bucle contenga más de una declaración simple: |
| |
| .. code-block:: c |
| |
| while (condición) { |
| if (test) |
| haz_eso(); |
| } |
| |
| 3.1) Espacios |
| ************* |
| |
| El estilo del kernel Linux para el uso de espacios depende (principalmente) |
| del uso de función versus uso de palabra clave. Utilice un espacio después |
| de (la mayoría de) las palabras clave. Las excepciones notables son sizeof, |
| typeof, alignof y __attribute__, que parecen algo así como funciones (y |
| generalmente se usan con paréntesis en Linux, aunque no son requeridos en |
| el idioma, como en: ``sizeof info`` después de que ``struct fileinfo info;`` |
| se declare). |
| |
| Así que use un espacio después de estas palabras clave:: |
| |
| if, switch, case, for, do, while |
| |
| pero no con sizeof, typeof, alignof, o __attribute__. Por ejemplo, |
| |
| .. code-block:: c |
| |
| |
| s = sizeof(struct file); |
| |
| No agregue espacios alrededor (dentro) de expresiones entre paréntesis. |
| Este ejemplo es **malo**: |
| |
| .. code-block:: c |
| |
| |
| s = sizeof( struct file ); |
| |
| Al declarar datos de puntero o una función que devuelve un tipo de puntero, |
| el uso preferido de ``*`` es adyacente al nombre del dato o nombre de la |
| función y no junto al nombre del tipo. Ejemplos: |
| |
| .. code-block:: c |
| |
| |
| char *linux_banner; |
| unsigned long long memparse(char *ptr, char **retptr); |
| char *match_strdup(substring_t *s); |
| |
| Use un espacio alrededor (a cada lado de) la mayoría de los operadores |
| binarios y ternarios, como cualquiera de estos:: |
| |
| = + - < > * / % | & ^ <= >= == != ? : |
| |
| pero sin espacio después de los operadores unarios:: |
| |
| & * + - ~ ! sizeof typeof alignof __attribute__ defined |
| |
| sin espacio antes de los operadores unarios de incremento y decremento del |
| sufijo:: |
| |
| ++ -- |
| |
| y sin espacio alrededor de los operadores de miembros de estructura ``.`` y |
| ``->``. |
| |
| No deje espacios en blanco al final de las líneas. Algunos editores con |
| ``inteligente`` sangría insertarán espacios en blanco al comienzo de las |
| nuevas líneas como sea apropiado, para que pueda comenzar a escribir la |
| siguiente línea de código de inmediato. Sin embargo, algunos de estos |
| editores no eliminan los espacios en blanco si finalmente no termina |
| poniendo una línea de código allí, como si dejara una línea en blanco. Como |
| resultado, termina con líneas que contienen espacios en blanco al final. |
| |
| Git le advertirá sobre los parches que introducen espacios en blanco al |
| final y puede, opcionalmente, eliminar los espacios en blanco finales por |
| usted; sin embargo, si se aplica una serie de parches, esto puede hacer que |
| los parches posteriores de la serie fallen al cambiar sus líneas de |
| contexto. |
| |
| |
| 4) Nomenclatura |
| --------------- |
| |
| C es un lenguaje espartano, y sus convenciones de nomenclatura deberían |
| seguir su ejemplo. A diferencia de los programadores de Modula-2 y Pascal, |
| los programadores de C no usan nombres cuquis como |
| EstaVariableEsUnContadorTemporal. Un programador de C lo llamaría |
| variable ``tmp``, que es mucho más fácil de escribir, y no es mas difícil |
| de comprender. |
| |
| SIN EMBARGO, mientras que los nombres de mayúsculas y minúsculas están mal |
| vistos, los nombres descriptivos para las variables globales son |
| imprescindibles. Llamar a una función global ``foo`` es un delito. |
| |
| Una variable GLOBAL (para usar solo si **realmente** las necesita) necesita |
| tener un nombre descriptivo, al igual que las funciones globales. Si tiene |
| una función que cuenta el número de usuarios activos, debe llamar a esta |
| ``contar_usuarios_activos()`` o similar, **no** debe llamarlo ``cntusr()``. |
| |
| Codificar el tipo de una función en el nombre (lo llamado notación húngara) |
| es estúpido: el compilador conoce los tipos de todos modos y puede |
| verificar estos, y solo confunde al programador. |
| |
| Los nombres de las variables LOCALES deben ser breves y directos. Si usted |
| tiene algún contador aleatorio de tipo entero, probablemente debería |
| llamarse ``i``. Llamarlo ``loop_counter`` no es productivo, si no hay |
| posibilidad de ser mal entendido. De manera similar, ``tmp`` puede ser casi |
| cualquier tipo de variable que se utiliza para contener un valor temporal. |
| |
| Si tiene miedo de mezclar los nombres de las variables locales, tiene otro |
| problema, que se denomina síndrome de |
| función-crecimiento-desequilibrio-de-hormona. Vea el capítulo 6 (Funciones). |
| |
| Para nombres de símbolos y documentación, evite introducir nuevos usos de |
| 'master / slave' (maestro / esclavo) (o 'slave' independientemente de |
| 'master') y 'lista negra / lista blanca' (backlist / whitelist). |
| |
| Los reemplazos recomendados para 'maestro / esclavo' son: |
| '{primary,main} / {secondary,replica,subordinate}' |
| '{initiator,requester} / {target,responder}' |
| '{controller,host} / {device,worker,proxy}' |
| 'leader / follower' |
| 'director / performer' |
| |
| Los reemplazos recomendados para 'backlist / whitelist' son: |
| 'denylist / allowlist' |
| 'blocklist / passlist' |
| |
| Las excepciones para la introducción de nuevos usos son mantener en espacio |
| de usuario una ABI/API, o al actualizar la especificación del código de un |
| hardware o protocolo existente (a partir de 2020) que requiere esos |
| términos. Para nuevas especificaciones, traduzca el uso de la terminología |
| de la especificación al estándar de código del kernel donde sea posible. |
| |
| 5) Typedefs |
| ----------- |
| |
| Por favor no use cosas como ``vps_t``. |
| Es un **error** usar typedef para estructuras y punteros. cuando ve un |
| |
| .. code-block:: c |
| |
| |
| vps_t a; |
| |
| en el código fuente, ¿qué significa? |
| En cambio, si dice |
| |
| .. code-block:: c |
| |
| struct virtual_container *a; |
| |
| puede decir qué es ``a`` en realidad. |
| |
| Mucha gente piensa que los typedefs ``ayudan a la legibilidad``. No. Son |
| útiles solamente para: |
| |
| (a) objetos totalmente opacos (donde el typedef se usa activamente para |
| **ocultar** cuál es el objeto). |
| |
| Ejemplo: ``pte_t`` etc. objetos opacos a los que solo puede acceder |
| usando las funciones de acceso adecuadas. |
| |
| .. note:: |
| |
| La opacidad y las ``funciones de acceso`` no son buenas por sí |
| mismas. La razón por la que los tenemos para cosas como pte_t, etc. |
| es que hay real y absolutamente **cero** información accesible de |
| forma portátil allí. |
| |
| (b) Tipos enteros claros, donde la abstracción **ayuda** a evitar |
| confusiones, ya sea ``int`` o ``long``. |
| |
| u8/u16/u32 son definiciones tipográficas perfectamente correctas |
| aunque encajan en la categoría (d) mejor que aquí. |
| |
| .. note:: |
| |
| De nuevo - debe haber una **razón** para esto. si algo es |
| ``unsigned long``, entonces no hay razón para hacerlo |
| |
| typedef unsigned long mis_flags_t; |
| |
| pero si hay una razón clara de por qué bajo ciertas circunstancias |
| podría ser un ``unsigned int`` y bajo otras configuraciones podría |
| ser ``unsigned long``, entonces, sin duda, adelante y use un typedef. |
| |
| (c) cuando lo use para crear literalmente un tipo **nuevo** para |
| comprobación de tipos. |
| |
| (d) Nuevos tipos que son idénticos a los tipos estándar C99, en ciertas |
| circunstancias excepcionales. |
| |
| Aunque sólo costaría un corto período de tiempo para los ojos y |
| cerebro para acostumbrarse a los tipos estándar como ``uint32_t``, |
| algunas personas se oponen a su uso de todos modos. |
| |
| Por lo tanto, los tipos ``u8/u16/u32/u64`` específicos de Linux y sus |
| equivalentes con signo, que son idénticos a los tipos estándar son |
| permitidos, aunque no son obligatorios en el nuevo código de su |
| elección. |
| |
| Al editar código existente que ya usa uno u otro conjunto de tipos, |
| debe ajustarse a las opciones existentes en ese código. |
| |
| (e) Tipos seguros para usar en el espacio de usuario. |
| |
| En ciertas estructuras que son visibles para el espacio de usuario, no |
| podemos requerir tipos C99 y o utilizat el ``u32`` anterior. Por lo |
| tanto, usamos __u32 y tipos similares en todas las estructuras que se |
| comparten con espacio de usuario. |
| |
| Tal vez también haya otros casos, pero la regla básicamente debería ser |
| NUNCA JAMÁS use un typedef a menos que pueda coincidir claramente con una |
| de estas reglas. |
| |
| En general, un puntero o una estructura que tiene elementos que pueden |
| ser razonablemente accedidos directamente, **nunca** deben ser un typedef. |
| |
| 6) Funciones |
| ------------ |
| |
| Las funciones deben ser cortas y dulces, y hacer una sola cosa. Deberían |
| caber en una o dos pantallas de texto (el tamaño de pantalla ISO/ANSI es |
| 80x24, como todos sabemos), y hacer una cosa y hacerla bien. |
| |
| La longitud máxima de una función es inversamente proporcional a la |
| complejidad y el nivel de sangría de esa función. Entonces, si tiene una |
| función conceptualmente simple que es solo una larga (pero simple) |
| declaración de case, donde tiene que hacer un montón de pequeñas cosas para |
| un montón de diferentes casos, está bien tener una función más larga. |
| |
| Sin embargo, si tiene una función compleja y sospecha que un estudiante de |
| primer año de secundaria menos que dotado podría no comprender de qué se |
| trata la función, debe adherirse a los límites máximos tanto más de |
| cerca. Use funciones auxiliares con nombres descriptivos (puede pedirle al |
| compilador que los alinee si cree que es crítico para el rendimiento, y |
| probablemente lo hará mejor de lo que usted hubiera hecho). |
| |
| Otra medida de la función es el número de variables locales. Estas no deben |
| exceder de 5 a 10, o está haciendo algo mal. Piense de nuevo en la función |
| y divida en partes más pequeñas. Un cerebro humano puede generalmente |
| realiza un seguimiento de aproximadamente 7 cosas diferentes, cualquier |
| elemento más y se confunde. Usted sabe que es brillante, pero tal vez le |
| gustaría entender lo que hizo dentro de 2 semanas. |
| |
| En los archivos fuente, separe las funciones con una línea en blanco. Si la |
| función es exportada, la macro **EXPORT** debería ponerse inmediatamente |
| después de la función de cierre de línea de llave. Por ejemplo: |
| |
| .. code-block:: c |
| |
| int sistema_corriendo(void) |
| { |
| return estado_sistema == SISTEMA_CORRIENDO; |
| } |
| EXPORT_SYMBOL(sistema_corriendo); |
| |
| 6.1) Prototipos de funciones |
| **************************** |
| |
| En los prototipos de funciones, incluya nombres de parámetros con sus tipos |
| de datos. Aunque esto no es requerido por el lenguaje C, se prefiere en |
| Linux porque es una forma sencilla de añadir información valiosa para el |
| lector. |
| |
| No utilice la palabra clave ``extern`` con declaraciones de función ya que |
| esto hace las líneas más largas y no es estrictamente necesario. |
| |
| Al escribir prototipos de funciones, mantenga el `orden de los elementos regular |
| <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_. |
| Por ejemplo, usando este ejemplo de declaración de función:: |
| |
| __init void * __must_check action(enum magic value, size_t size, u8 count, |
| char *fmt, ...) __printf(4, 5) __malloc; |
| |
| El orden preferido de elementos para un prototipo de función es: |
| |
| - clase de almacenamiento (a continuación, ``static __always_inline``, |
| teniendo en cuenta que ``__always_inline`` es técnicamente un atributo |
| pero se trata como ``inline``) |
| - atributos de clase de almacenamiento (aquí, ``__init`` -- es decir, |
| declaraciones de sección, pero también cosas como ``__cold``) |
| - tipo de retorno (aquí, ``void *``) |
| - atributos de tipo de retorno (aquí, ``__must_check``) |
| - nombre de la función (aquí, ``action``) |
| - parámetros de la función (aquí, ``(enum magic value, size_t size, u8 count, char *fmt, ...)``, |
| teniendo en cuenta que los nombres de los parámetros siempre deben |
| incluirse) |
| - atributos de parámetros de función (aquí, ``__printf(4, 5)``) |
| - atributos de comportamiento de la función (aquí, ``__malloc``) |
| |
| Tenga en cuenta que para una **definición** de función (es decir, el cuerpo |
| real de la función), el compilador no permite atributos de parámetros de |
| función después de parámetros de la función. En estos casos, deberán ir |
| tras los atributos de clase (por ejemplo, tenga en cuenta el cambio de |
| posición de ``__printf(4, 5)`` a continuación, en comparación con el |
| ejemplo de **declaración** anterior):: |
| |
| static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value, |
| size_t size, u8 count, char *fmt, ...) __malloc |
| { |
| ... |
| } |
| |
| 7) Salida centralizada de funciones |
| ----------------------------------- |
| |
| Aunque desaprobado por algunas personas, el equivalente de la instrucción |
| goto es utilizado con frecuencia por los compiladores, en forma de |
| instrucción de salto incondicional. |
| |
| La declaración goto es útil cuando una función sale desde múltiples |
| ubicaciones y se deben realizar algunos trabajos comunes, como la limpieza. |
| Si no se necesita limpieza, entonces simplemente haga return directamente. |
| |
| Elija nombres de etiquetas que digan qué hace el goto o por qué existe el |
| goto. Un ejemplo de un buen nombre podría ser ``out_free_buffer:`` |
| (``salida_liberar_buffer``) si al irse libera ``buffer``. Evite usar |
| nombres GW-BASIC como ``err1:`` y ``err2:``, ya que tendría que volver a |
| numerarlos si alguna vez agrega o elimina rutas de salida, y hacen que sea |
| difícil de verificar que sean correctos, de todos modos. |
| |
| La razón para usar gotos es: |
| |
| - Las declaraciones incondicionales son más fáciles de entender y seguir. |
| - se reduce el anidamiento |
| - errores al no actualizar los puntos de salida individuales al hacer |
| modificaciones son evitados |
| - ahorra el trabajo del compilador de optimizar código redundante ;) |
| |
| .. code-block:: c |
| |
| int fun(int a) |
| { |
| int result = 0; |
| char *buffer; |
| |
| buffer = kmalloc(SIZE, GFP_KERNEL); |
| if (!buffer) |
| return -ENOMEM; |
| |
| if (condition1) { |
| while (loop1) { |
| ... |
| } |
| result = 1; |
| goto out_free_buffer; |
| } |
| ... |
| out_free_buffer: |
| kfree(buffer); |
| return result; |
| } |
| |
| Un tipo común de error a tener en cuenta es "un error de error" que es algo |
| así: |
| |
| .. code-block:: c |
| |
| err: |
| kfree(foo->bar); |
| kfree(foo); |
| return ret; |
| |
| El error en este código es que en algunas rutas de salida, ``foo`` es NULL. |
| Normalmente la solución para esto es dividirlo en dos etiquetas de error |
| ``err_free_bar:`` y ``err_free_foo:``: |
| |
| .. code-block:: c |
| |
| err_free_bar: |
| kfree(foo->bar); |
| err_free_foo: |
| kfree(foo); |
| return ret; |
| |
| Idealmente, debería simular errores para probar todas las rutas de salida. |
| |
| |
| 8) Comentarios |
| -------------- |
| |
| Los comentarios son buenos, pero también existe el peligro de comentar |
| demasiado. NUNCA trate de explicar CÓMO funciona su código en un |
| comentario: es mucho mejor escribir el código para que el |
| **funcionamiento** sea obvio y es una pérdida de tiempo explicar código mal |
| escrito. |
| |
| Generalmente, desea que sus comentarios digan QUÉ hace su código, no CÓMO. |
| Además, trate de evitar poner comentarios dentro del cuerpo de una función: |
| si la función es tan compleja que necesita comentar por separado partes de |
| esta, probablemente debería volver al capítulo 6 una temporada. Puede |
| hacer pequeños comentarios para notar o advertir sobre algo particularmente |
| inteligente (o feo), pero trate de evitar el exceso. En su lugar, ponga los |
| comentarios al principio de la función, diga a la gente lo que hace y |
| posiblemente POR QUÉ hace esto. |
| |
| Al comentar las funciones de la API del kernel, utilice el formato |
| kernel-doc. Consulte los archivos en :ref:`Documentation/doc-guide/ <doc_guide>` |
| y ``scripts/kernel-doc`` para más detalles. |
| |
| El estilo preferido para comentarios largos (de varias líneas) es: |
| |
| .. code-block:: c |
| |
| /* |
| * Este es el estilo preferido para comentarios |
| * multilínea en el código fuente del kernel Linux. |
| * Por favor, utilícelo constantemente. |
| * |
| * Descripción: Una columna de asteriscos en el lado izquierdo, |
| * con líneas iniciales y finales casi en blanco. |
| */ |
| |
| Para archivos en net/ y drivers/net/, el estilo preferido para comentarios |
| largos (multi-linea) es un poco diferente. |
| |
| .. code-block:: c |
| |
| /* El estilo de comentario preferido para archivos en net/ y drivers/net |
| * se asemeja a esto. |
| * |
| * Es casi lo mismo que el estilo de comentario generalmente preferido, |
| * pero no hay una línea inicial casi en blanco. |
| */ |
| |
| También es importante comentar los datos, ya sean tipos básicos o |
| derivados. Para este fin, use solo una declaración de datos por línea (sin |
| comas para múltiples declaraciones de datos). Esto le deja espacio para un |
| pequeño comentario sobre cada elemento, explicando su uso. |
| |
| 9) Has hecho un desastre |
| --------------------------- |
| |
| Está bien, todos lo hacemos. Probablemente un antiguo usuario de Unix le |
| haya dicho que ``GNU emacs`` formatea automáticamente las fuentes C por |
| usted, y ha notado que sí, lo hace, pero los por defecto que tiene son |
| menos que deseables (de hecho, son peores que los aleatorios) escribiendo - |
| un número infinito de monos escribiendo en GNU emacs nunca harán un buen |
| programa). |
| |
| Por lo tanto, puede deshacerse de GNU emacs o cambiarlo y usar valores más |
| sanos. Para hacer esto último, puede pegar lo siguiente en su archivo |
| .emacs: |
| |
| .. code-block:: none |
| |
| (defun c-lineup-arglist-tabs-only (ignored) |
| "Line up argument lists by tabs, not spaces" |
| (let* ((anchor (c-langelem-pos c-syntactic-element)) |
| (column (c-langelem-2nd-pos c-syntactic-element)) |
| (offset (- (1+ column) anchor)) |
| (steps (floor offset c-basic-offset))) |
| (* (max steps 1) |
| c-basic-offset))) |
| |
| (dir-locals-set-class-variables |
| 'linux-kernel |
| '((c-mode . ( |
| (c-basic-offset . 8) |
| (c-label-minimum-indentation . 0) |
| (c-offsets-alist . ( |
| (arglist-close . c-lineup-arglist-tabs-only) |
| (arglist-cont-nonempty . |
| (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only)) |
| (arglist-intro . +) |
| (brace-list-intro . +) |
| (c . c-lineup-C-comments) |
| (case-label . 0) |
| (comment-intro . c-lineup-comment) |
| (cpp-define-intro . +) |
| (cpp-macro . -1000) |
| (cpp-macro-cont . +) |
| (defun-block-intro . +) |
| (else-clause . 0) |
| (func-decl-cont . +) |
| (inclass . +) |
| (inher-cont . c-lineup-multi-inher) |
| (knr-argdecl-intro . 0) |
| (label . -1000) |
| (statement . 0) |
| (statement-block-intro . +) |
| (statement-case-intro . +) |
| (statement-cont . +) |
| (substatement . +) |
| )) |
| (indent-tabs-mode . t) |
| (show-trailing-whitespace . t) |
| )))) |
| |
| (dir-locals-set-directory-class |
| (expand-file-name "~/src/linux-trees") |
| 'linux-kernel) |
| |
| Esto hará que emacs funcione mejor con el estilo de código del kernel para |
| C en archivos bajo ``~/src/linux-trees``. |
| |
| Pero incluso si no logra que emacs realice un formateo correcto, no todo |
| está perdido: use ``indent``. |
| |
| Ahora bien, de nuevo, la sangría de GNU tiene la misma configuración de |
| muerte cerebral que GNU emacs tiene, por lo que necesita darle algunas |
| opciones de línea de comando. Sin embargo, eso no es tan malo, porque |
| incluso los creadores de GNU indent reconocen la autoridad de K&R (la gente |
| de GNU no es mala, solo están gravemente equivocados en este asunto), por |
| lo que simplemente de a la sangría las opciones ``-kr -i8`` (significa |
| ``K&R, guiones de 8 caracteres``), o use ``scripts/Lindent``, que indenta |
| con ese estilo. |
| |
| ``indent`` tiene muchas opciones, y especialmente cuando se trata de |
| comentar reformateos, es posible que desee echar un vistazo a la página del |
| manual. Pero recuerde: ``indent`` no es la solución para una mala |
| programación. |
| |
| Tenga en cuenta que también puede usar la herramienta ``clang-format`` para |
| ayudarlo con estas reglas, para volver a formatear rápidamente partes de su |
| código automáticamente, y revisar archivos completos para detectar errores |
| de estilo del código, errores tipográficos y posibles mejoras. También es |
| útil para ordenar ``#includes``, para alinear variables/macros, para |
| redistribuir texto y otras tareas similares. Vea el archivo |
| :ref:`Documentation/dev-tools/clang-format.rst <clangformat>` para más |
| detalles. |
| |
| 10) Archivos de configuración de Kconfig |
| ---------------------------------------- |
| |
| Para todos los archivos de configuración de Kconfig* en todo el árbol |
| fuente, la sangría es algo diferente. Las líneas bajo una definición |
| ``config`` están indentadas con una tabulación, mientras que el texto de |
| ayuda tiene una sangría adicional de dos espacios. Ejemplo:: |
| |
| config AUDIT |
| bool "Soporte para auditar" |
| depends on NET |
| help |
| Habilita la infraestructura de auditoría que se puede usar con otro |
| subsistema kernel, como SELinux (que requiere esto para |
| registro de salida de mensajes avc). No hace auditoría de llamadas al |
| sistema sin CONFIG_AUDITSYSCALL. |
| |
| Características seriamente peligrosas (como soporte de escritura para |
| ciertos filesystems) deben anunciar esto de forma destacada en su cadena de |
| solicitud:: |
| |
| config ADFS_FS_RW |
| bool "ADFS write support (DANGEROUS)" |
| depends on ADFS_FS |
| ... |
| |
| Para obtener la documentación completa sobre los archivos de configuración, |
| consulte el archivo Documentation/kbuild/kconfig-language.rst. |
| |
| |
| 11) Estructuras de datos |
| ------------------------ |
| |
| Las estructuras de datos que tienen visibilidad fuera del contexto de un |
| solo subproceso en el que son creadas y destruidas, siempre debe tener |
| contadores de referencia. En el kernel, la recolección de basura no existe |
| (y fuera, la recolección de basura del kernel es lenta e ineficiente), lo |
| que significa que absolutamente **tiene** para hacer referencia y contar |
| todos sus usos. |
| |
| El conteo de referencias significa que puede evitar el bloqueo y permite |
| que múltiples usuarios tengan acceso a la estructura de datos en paralelo - |
| y no tengan que preocuparse de que la estructura, de repente, desaparezca |
| debajo de su control, solo porque durmieron o hicieron otra cosa por un |
| tiempo. |
| |
| Tenga en cuenta que el bloqueo **no** reemplaza el recuento de referencia. |
| El bloqueo se utiliza para mantener la coherencia de las estructuras de |
| datos, mientras que la referencia y contar es una técnica de gestión de |
| memoria. Por lo general, ambos son necesarios, y no deben confundirse entre |
| sí. |
| |
| De hecho, muchas estructuras de datos pueden tener dos niveles de conteo de |
| referencias, cuando hay usuarios de diferentes ``clases``. El conteo de |
| subclases cuenta el número de usuarios de la subclase y disminuye el conteo |
| global solo una vez, cuando el recuento de subclases llega a cero. |
| |
| Se pueden encontrar ejemplos de este tipo de ``recuento de referencias de |
| niveles múltiples`` en la gestión de memoria (``struct mm_struct``: |
| mm_users y mm_count), y en código del sistema de archivos |
| (``struct super_block``: s_count y s_active). |
| |
| Recuerde: si otro hilo puede encontrar su estructura de datos y usted no |
| tiene un recuento de referencias, es casi seguro que tiene un error. |
| |
| 12) Macros, Enums y RTL |
| ------------------------ |
| |
| Los nombres de macros que definen constantes y etiquetas en enumeraciones |
| (enums) están en mayúsculas. |
| |
| .. code-block:: c |
| |
| #define CONSTANTE 0x12345 |
| |
| Se prefieren los enums cuando se definen varias constantes relacionadas. |
| |
| Se aprecian los nombres de macro en MAYÚSCULAS, pero las macros que se |
| asemejan a funciones puede ser nombradas en minúscula. |
| |
| Generalmente, las funciones en línea son preferibles a las macros que se |
| asemejan a funciones. |
| |
| Las macros con varias instrucciones deben contenerse en un bloque do-while: |
| |
| .. code-block:: c |
| |
| #define macrofun(a, b, c) \ |
| do { \ |
| if (a == 5) \ |
| haz_esto(b, c); \ |
| } while (0) |
| |
| Cosas a evitar al usar macros: |
| |
| 1) macros que afectan el flujo de control: |
| |
| .. code-block:: c |
| |
| #define FOO(x) \ |
| do { \ |
| if (blah(x) < 0) \ |
| return -EBUGGERED; \ |
| } while (0) |
| |
| es una **muy** mala idea. Parece una llamada de función pero sale de la |
| función de ``llamada``; no rompa los analizadores internos de aquellos que |
| leerán el código. |
| |
| 2) macros que dependen de tener una variable local con un nombre mágico: |
| |
| .. code-block:: c |
| |
| #define FOO(val) bar(index, val) |
| |
| puede parecer algo bueno, pero es confuso como el infierno cuando uno lee |
| el código, y es propenso a romperse por cambios aparentemente inocentes. |
| |
| 3) macros con argumentos que se usan como valores l: FOO(x) = y; le van |
| a morder si alguien, por ejemplo, convierte FOO en una función en línea. |
| |
| 4) olvidarse de la precedencia: las macros que definen constantes usando |
| expresiones deben encerrar la expresión entre paréntesis. Tenga cuidado con |
| problemas similares con macros usando parámetros. |
| |
| .. code-block:: c |
| |
| #define CONSTANTE 0x4000 |
| #define CONSTEXP (CONSTANTE | 3) |
| |
| 5) colisiones de espacio de nombres ("namespace") al definir variables |
| locales en macros que se asemejan a funciones: |
| |
| .. code-block:: c |
| |
| #define FOO(x) \ |
| ({ \ |
| typeof(x) ret; \ |
| ret = calc_ret(x); \ |
| (ret); \ |
| }) |
| |
| ret es un nombre común para una variable local -es menos probable que |
| __foo_ret colisione (coincida) con una variable existente. |
| |
| El manual de cpp trata las macros de forma exhaustiva. El manual interno de |
| gcc también cubre RTL, que se usa frecuentemente con lenguaje ensamblador |
| en el kernel. |
| |
| 13) Imprimir mensajes del kernel |
| -------------------------------- |
| |
| A los desarrolladores del kernel les gusta ser vistos como alfabetizados. |
| Cuide la ortografía de los mensajes del kernel para causar una buena |
| impresión. No utilice contracciones incorrectas como ``dont``; use |
| ``do not`` o ``don't`` en su lugar. Haga sus mensajes concisos, claros e |
| inequívocos. |
| |
| Los mensajes del kernel no tienen que terminar con un punto. |
| |
| Imprimir números entre paréntesis (%d) no agrega valor y debe evitarse. |
| |
| Hay varias modelos de macros de diagnóstico de driver en <linux/dev_printk.h> |
| que debe usar para asegurarse de que los mensajes coincidan con el |
| dispositivo correcto y driver, y están etiquetados con el nivel correcto: |
| dev_err(), dev_warn(), dev_info(), y así sucesivamente. Para mensajes que |
| no están asociados con un dispositivo particular, <linux/printk.h> define |
| pr_notice(), pr_info(), pr_warn(), pr_err(), etc. |
| |
| Crear buenos mensajes de depuración puede ser todo un desafío; y una vez |
| los tiene, pueden ser de gran ayuda para la resolución remota de problemas. |
| Sin embargo, la impresión de mensajes de depuración se maneja de manera |
| diferente a la impresión de otros mensajes que no son de depuración. |
| Mientras que las otras funciones pr_XXX() se imprimen incondicionalmente, |
| pr_debug() no lo hace; se compila fuera por defecto, a menos que DEBUG sea |
| definido o se establezca CONFIG_DYNAMIC_DEBUG. Eso es cierto para dev_dbg() |
| también, y una convención relacionada usa VERBOSE_DEBUG para agregar |
| mensajes dev_vdbg() a los ya habilitados por DEBUG. |
| |
| Muchos subsistemas tienen opciones de depuración de Kconfig para activar |
| -DDEBUG en el Makefile correspondiente; en otros casos, los archivos |
| usan #define DEBUG. Y cuando un mensaje de depuración debe imprimirse |
| incondicionalmente, por ejemplo si es ya dentro de una sección #ifdef |
| relacionada con la depuración, printk(KERN_DEBUG ...) puede ser usado. |
| |
| 14) Reservando memoria |
| ---------------------- |
| |
| El kernel proporciona los siguientes asignadores de memoria de propósito |
| general: kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() y |
| vzalloc(). Consulte la documentación de la API para obtener más información. |
| a cerca de ellos. :ref:`Documentation/core-api/memory-allocation.rst |
| <memory_allocation>` |
| |
| La forma preferida para pasar el tamaño de una estructura es la siguiente: |
| |
| .. code-block:: c |
| |
| p = kmalloc(sizeof(*p), ...); |
| |
| La forma alternativa donde se deletrea el nombre de la estructura perjudica |
| la legibilidad, y presenta una oportunidad para un error cuando se cambia |
| el tipo de variable de puntero, pero el tamaño correspondiente de eso que |
| se pasa a un asignador de memoria no. |
| |
| Convertir el valor devuelto, que es un puntero vacío, es redundante. La |
| conversión desde el puntero vacío a cualquier otro tipo de puntero está |
| garantizado por la programación en idioma C. |
| |
| La forma preferida para asignar una matriz es la siguiente: |
| |
| .. code-block:: c |
| |
| p = kmalloc_array(n, sizeof(...), ...); |
| |
| La forma preferida para asignar una matriz a cero es la siguiente: |
| |
| .. code-block:: c |
| |
| p = kcalloc(n, sizeof(...), ...); |
| |
| Ambos casos verifican el desbordamiento en el tamaño de asignación n * |
| sizeof (...), y devuelven NULL si esto ocurrió. |
| |
| Todas estas funciones de asignación genéricas emiten un volcado de pila |
| (" stack dump") en caso de fallo cuando se usan sin __GFP_NOWARN, por lo |
| que no sirve de nada emitir un mensaje de fallo adicional cuando se |
| devuelva NULL. |
| |
| 15) La enfermedad de inline |
| ---------------------------- |
| |
| Parece haber una común percepción errónea de que gcc tiene una magica |
| opción "hazme más rápido" de aceleración, llamada ``inline`` (en línea). |
| Mientras que el uso de inlines puede ser apropiado (por ejemplo, como un |
| medio para reemplazar macros, consulte el Capítulo 12), muy a menudo no lo |
| es. El uso abundante de la palabra clave inline conduce a una mayor kernel, |
| que a su vez ralentiza el sistema en su conjunto, debido a una mayor huella |
| de icache para la CPU, y sencillamente porque hay menos memoria disponible |
| para el pagecache. Solo piense en esto; un fallo en la memoria caché de la |
| página provoca una búsqueda de disco, que tarda fácilmente 5 milisegundos. |
| Hay MUCHOS ciclos de CPU que puede entrar en estos 5 milisegundos. |
| |
| Una razonable regla general es no poner funciones inline que tengan más de |
| 3 líneas de código en ellas. Una excepción a esta regla son los casos en |
| que se sabe que un parámetro es una constante en tiempo de compilación, y |
| como resultado de esto, usted *sabe*, el compilador podrá optimizar la |
| mayor parte de su función en tiempo de compilación. Para un buen ejemplo de |
| este último caso, véase la función en línea kmalloc(). |
| |
| A menudo, la gente argumenta que agregar funciones en línea que son |
| estáticas y se usan solo una vez, es siempre una victoria ya que no hay |
| perdida de espacio. Mientras esto es técnicamente correcto, gcc es capaz de |
| incorporarlos automáticamente sin ayuda, y esta el problema de |
| mantenimiento de eliminar el inline, cuando un segundo usuario supera el |
| valor potencial de la pista que le dice a gcc que haga algo que habría |
| hecho de todos modos. |
| |
| 16) Valores devueltos por función y sus nombres |
| ----------------------------------------------- |
| |
| Las funciones pueden devolver valores de muchos tipos diferentes, y uno de |
| lo más común es un valor que indica si la función tuvo éxito o ha fallado. |
| Dicho valor se puede representar como un número entero de código de error |
| (-Exxx = falla, 0 = éxito) o un booleano ``con éxito`` (0 = falla, distinto |
| de cero = éxito). |
| |
| La mezcla de estos dos tipos de representaciones es una fuente fértil de |
| errores difíciles de encontrar. Si el lenguaje C incluyera una fuerte |
| distinción entre enteros y booleanos, el compilador encontraría estos |
| errores por nosotros... pero no lo hace. Para ayudar a prevenir tales |
| errores, siga siempre esta convención:: |
| |
| Si el nombre de una función es una acción o un comando imperativo, |
| la función debe devolver un número entero de código de error. si el nombre |
| es un predicado, la función debe devolver un valor booleano "exitoso". |
| |
| Por ejemplo, ``agregar trabajo`` es un comando, y la función |
| agregar_trabajo() devuelve 0 en caso de éxito o -EBUSY en caso de fracaso. |
| De la misma manera, ``dispositivo PCI presente`` es un predicado, y la |
| función pci_dev_present() devuelve 1 si tiene éxito en encontrar un |
| dispositivo coincidente o 0 si no es así. |
| |
| Todas las funciones EXPORTed (exportadas) deben respetar esta convención, |
| al igual que todas las funciones publicas. Las funciones privadas |
| (estáticas) no lo necesitan, pero es recomendado que lo hagan. |
| |
| Las funciones cuyo valor devuelto es el resultado real de un cálculo, en |
| lugar de una indicación de si el cómputo tuvo éxito, no están sujetas a |
| esta regla. Generalmente indican fallo al devolver valores fuera del rango |
| de resultados. Los ejemplos típicos serían funciones que devuelven |
| punteros; estos usan NULL o el mecanismo ERR_PTR para informar de fallos. |
| |
| 17) Usando bool |
| ---------------- |
| |
| El tipo bool del kernel Linux es un alias para el tipo C99 _Bool. Los |
| valores booleanos pueden solo evaluar a 0 o 1, y la conversión implícita o |
| explícita a bool convierte automáticamente el valor en verdadero o falso. |
| Cuando se utilizan tipos booleanos, |
| !! no se necesita construcción, lo que elimina una clase de errores. |
| |
| Cuando se trabaja con valores booleanos, se deben usar las definiciones |
| verdadera y falsa, en lugar de 1 y 0. |
| |
| Los tipos de devolución de función bool y las variables de pila siempre |
| se pueden usar cuando esto sea adecuado. Se recomienda el uso de bool para |
| mejorar la legibilidad y, a menudo, es una mejor opción que 'int' para |
| almacenar valores booleanos. |
| |
| No use bool si el diseño de la línea de caché o el tamaño del valor son |
| importantes, ya que su tamaño y la alineación varía según la arquitectura |
| compilada. Las estructuras que son optimizadas para la alineación y el |
| tamaño no debe usar bool. |
| |
| Si una estructura tiene muchos valores verdadero/falso, considere |
| consolidarlos en un bitfield con miembros de 1 bit, o usando un tipo de |
| ancho fijo apropiado, como u8. |
| |
| De manera similar, para los argumentos de función, se pueden consolidar |
| muchos valores verdaderos/falsos en un solo argumento bit a bit 'flags' y |
| 'flags' a menudo, puede ser una alternativa de argumento más legible si los |
| sitios de llamada tienen constantes desnudas de tipo verdaderas/falsas. |
| |
| De lo contrario, el uso limitado de bool en estructuras y argumentos puede |
| mejorar la legibilidad. |
| |
| 18) No reinvente las macros del kernel |
| --------------------------------------- |
| |
| El archivo de cabecera include/linux/kernel.h contiene una serie de macros |
| que debe usar, en lugar de programar explícitamente alguna variante de |
| estos por usted mismo. Por ejemplo, si necesita calcular la longitud de una |
| matriz, aproveche la macro |
| |
| .. code-block:: c |
| |
| #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
| |
| De manera similar, si necesita calcular el tamaño de algún miembro de la |
| estructura, use |
| |
| .. code-block:: c |
| |
| #define sizeof_field(t, f) (sizeof(((t*)0)->f)) |
| |
| También hay macros min() y max() que realizan una verificación estricta de |
| tipos si lo necesita. Siéntase libre de leer detenidamente ese archivo de |
| encabezado para ver qué más ya está definido y que no debe reproducir en su |
| código. |
| |
| 19) Editores modeline y otros desastres |
| --------------------------------------- |
| |
| Algunos editores pueden interpretar la información de configuración |
| incrustada en los archivos fuente, indicado con marcadores especiales. Por |
| ejemplo, emacs interpreta las líneas marcadas como esto: |
| |
| .. code-block:: c |
| |
| -*- mode: c -*- |
| |
| O así: |
| |
| .. code-block:: c |
| |
| /* |
| Local Variables: |
| compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" |
| End: |
| */ |
| |
| Vim interpreta los marcadores que se ven así: |
| |
| .. code-block:: c |
| |
| /* vim:set sw=8 noet */ |
| |
| No incluya ninguno de estos en los archivos fuente. La gente tiene sus |
| propias configuraciones del editor, y sus archivos de origen no deben |
| anularlos. Esto incluye marcadores para sangría y configuración de modo. |
| La gente puede usar su propio modo personalizado, o puede tener algún otro |
| método mágico para que la sangría funcione correctamente. |
| |
| |
| 20) Ensamblador inline |
| ----------------------- |
| |
| En el código específico de arquitectura, es posible que deba usar |
| ensamblador en línea para interactuar con funcionalidades de CPU o |
| plataforma. No dude en hacerlo cuando sea necesario. Sin embargo, no use |
| ensamblador en línea de forma gratuita cuando C puede hacer el trabajo. |
| Puede y debe empujar el hardware desde C cuando sea posible. |
| |
| Considere escribir funciones auxiliares simples que envuelvan bits comunes |
| de ensamblador, en lugar de escribirlos repetidamente con ligeras |
| variaciones. Recuerde que el ensamblador en línea puede usar parámetros C. |
| |
| Las funciones de ensamblador grandes y no triviales deben ir en archivos .S, |
| con su correspondientes prototipos de C definidos en archivos de encabezado |
| en C. Los prototipos de C para el ensamblador deben usar ``asmlinkage``. |
| |
| Es posible que deba marcar su declaración asm como volátil, para evitar que |
| GCC la elimine si GCC no nota ningún efecto secundario. No siempre es |
| necesario hacerlo, sin embargo, y hacerlo innecesariamente puede limitar la |
| optimización. |
| |
| Al escribir una sola declaración de ensamblador en línea que contiene |
| múltiples instrucciones, ponga cada instrucción en una línea separada en |
| una string separada, y termine cada string excepto la última con ``\n\t`` |
| para indentar correctamente la siguiente instrucción en la salida en |
| ensamblador: |
| |
| .. code-block:: c |
| |
| asm ("magic %reg1, #42\n\t" |
| "more_magic %reg2, %reg3" |
| : /* outputs */ : /* inputs */ : /* clobbers */); |
| |
| 21) Compilación condicional |
| --------------------------- |
| |
| Siempre que sea posible, no use condicionales de preprocesador (#if, |
| #ifdef) en archivos .c; de lo contrario, el código es más difícil de leer y |
| la lógica más difícil de seguir. En cambio, use dichos condicionales en un |
| archivo de encabezado que defina funciones para usar en esos archivos .c, |
| proporcionando versiones de código auxiliar sin operación en el caso #else, |
| y luego llame a estas funciones incondicionalmente desde archivos .c. El |
| compilador evitará generar cualquier código para las llamadas restantes, |
| produciendo resultados idénticos, pero la lógica es fácil de seguir. |
| |
| Prefiera compilar funciones completas, en lugar de porciones de funciones o |
| porciones de expresiones. En lugar de poner un ifdef en una expresión, |
| divida la totalidad de la expresión con una función de ayuda independiente |
| y aplique el condicional a esa función. |
| |
| Si tiene una función o variable que puede potencialmente quedar sin usar en |
| una configuración en particular, y el compilador advertiría sobre su |
| definición sin usar, marque la definición como __maybe_unused en lugar de |
| envolverla en un preprocesador condicional. (Sin embargo, si una función o |
| variable *siempre* acaba sin ser usada, bórrela.) |
| |
| Dentro del código, cuando sea posible, use la macro IS_ENABLED para |
| convertir un símbolo Kconfig en una expresión booleana de C, y utilícelo en |
| un condicional de C normal: |
| |
| .. code-block:: c |
| |
| if (IS_ENABLED(CONFIG_SOMETHING)) { |
| ... |
| } |
| |
| El compilador "doblará"" constantemente el condicional e incluirá o |
| excluirá el bloque de código al igual que con un #ifdef, por lo que esto no |
| agregará ningún tiempo de gastos generales en ejecución. Sin embargo, este |
| enfoque todavía permite que el compilador de C vea el código dentro del |
| bloque, y verifique que sea correcto (sintaxis, tipos, símbolo, referencias, |
| etc.). Por lo tanto, aún debe usar un #ifdef si el código dentro del bloque |
| hace referencia a símbolos que no existirán si no se cumple la condición. |
| |
| Al final de cualquier bloque #if o #ifdef no trivial (más de unas pocas |
| líneas), incluya un comentario después de #endif en la misma línea, |
| anotando la expresión condicional utilizada. Por ejemplo: |
| |
| .. code-block:: c |
| |
| #ifdef CONFIG_SOMETHING |
| ... |
| #endif /* CONFIG_SOMETHING */ |
| |
| 22) No rompa el kernel |
| ----------------------- |
| |
| En general, la decisión de romper el kernel pertenece al usuario, más que |
| al desarrollador del kernel. |
| |
| Evite el panic() |
| **************** |
| |
| panic() debe usarse con cuidado y principalmente solo durante el arranque |
| del sistema. panic() es, por ejemplo, aceptable cuando se queda sin memoria |
| durante el arranque y no puede continuar. |
| |
| Use WARN() en lugar de BUG() |
| **************************** |
| |
| No agregue código nuevo que use cualquiera de las variantes BUG(), como |
| BUG(), BUG_ON() o VM_BUG_ON(). En su lugar, use una variante WARN*(), |
| preferiblemente WARN_ON_ONCE(), y posiblemente con código de recuperación. |
| El código de recuperación no es requerido si no hay una forma razonable de |
| recuperar, al menos parcialmente. |
| |
| "Soy demasiado perezoso para tener en cuenta los errores" no es una excusa |
| para usar BUG(). Importantes corrupciones internas sin forma de continuar |
| aún pueden usar BUG(), pero necesitan una buena justificación. |
| |
| Use WARN_ON_ONCE() en lugar de WARN() o WARN_ON() |
| ************************************************* |
| |
| Generalmente, se prefiere WARN_ON_ONCE() a WARN() o WARN_ON(), porque es |
| común que una condición de advertencia dada, si ocurre, ocurra varias |
| veces. Esto puede llenar el registro del kernel, e incluso puede ralentizar |
| el sistema lo suficiente como para que el registro excesivo se convierta en |
| su propio, adicional problema. |
| |
| No haga WARN a la ligera |
| ************************ |
| |
| WARN*() está diseñado para situaciones inesperadas que nunca deberían |
| suceder. Las macros WARN*() no deben usarse para nada que se espera que |
| suceda durante un funcionamiento normal. No hay "checkeos" previos o |
| posteriores a la condición, por ejemplo. De nuevo: WARN*() no debe usarse |
| para una condición esperada que vaya a activarse fácilmente, por ejemplo, |
| mediante acciones en el espacio del usuario. pr_warn_once() es una |
| alternativa posible, si necesita notificar al usuario de un problema. |
| |
| No se preocupe sobre panic_on_warn de usuarios |
| ********************************************** |
| |
| Algunas palabras más sobre panic_on_warn: Recuerde que ``panic_on_warn`` es |
| una opción disponible del kernel, y que muchos usuarios configuran esta |
| opción. Esta es la razón por la que hay un artículo de "No haga WARN a la |
| ligera", arriba. Sin embargo, la existencia de panic_on_warn de usuarios no |
| es una razón válida para evitar el uso juicioso de WARN*(). Esto se debe a |
| que quien habilita panic_on_warn, explícitamente pidió al kernel que |
| fallara si se dispara un WARN*(), y tales usuarios deben estar preparados |
| para afrontar las consecuencias de un sistema que es algo más probable que |
| se rompa. |
| |
| Use BUILD_BUG_ON() para aserciones en tiempo de compilación |
| *********************************************************** |
| |
| El uso de BUILD_BUG_ON() es aceptable y recomendado, porque es una aserción |
| en tiempo de compilación, que no tiene efecto en tiempo de ejecución. |
| |
| Apéndice I) Referencias |
| ----------------------- |
| |
| The C Programming Language, Segunda edicion |
| por Brian W. Kernighan and Dennis M. Ritchie. |
| Prentice Hall, Inc., 1988. |
| ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback). |
| |
| The Practice of Programming |
| por Brian W. Kernighan and Rob Pike. |
| Addison-Wesley, Inc., 1999. |
| ISBN 0-201-61586-X. |
| |
| manuales GCC - en cumplimiento con K&R y este texto - para cpp, gcc, |
| detalles de gcc y sangría, todo disponible en https://www.gnu.org/manual/ |
| |
| WG14 es el grupo de trabajo de estandarización internacional de la |
| programación en lenguaje C, URL: http://www.open-std.org/JTC1/SC22/WG14/ |
| |
| :ref:`process/coding-style.rst <codingstyle>` del kernel, por greg@kroah.com at OLS 2002: |
| http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ |