Guía de Estilo para lenguaje C.

Instituto de Ingeniería Eléctrica, Facultad de Ingeniería.
Universidad Mayor de la República. Montevideo, URUGUAY.
Abril, 1998.

1. Propósito.
2. Alcance.
3. Organización de Archivos.
4. Declaración de Variables.
5. Funciones.
6. Comentarios.
7. Sentencias.
8. Operadores.
9. Espacios en blanco.
10. Constantes.
11. Compilación Condicional.
12. Portabilidad.
13. ANSI C.
14.Varios.
15. Conclusión.
16. Referencias.

1. Propósito.

Este documento define un estilo de codificación en el lenguaje de programación C a través de un conjunto de normas y recomendaciones. Se pretende que este estilo ayude a construir programas correctos, entendibles y fáciles de mantener.

En este documento, una "norma" es una regla que debe cumplirse obligatoriamente; una "recomendación" es una regla válida en general, pero que puede admitir o requerir excepciones.

2. Alcance.

Este documento trata exclisivamente del estilo de programación en lenguaje C en cuanto a codificación. No trata cuestiones de diseño, organización funcional ni otras que hacen a la buena construcción de los programas.

3. Organización de archivos.

Convención de nombres.

Se usarán las siguientes convenciones de nombres de archivos:

Archivos de código fuente.

Norma: Todos los archivos tendrán leyenda de derechos de autor.
Todos los archivos de código fuente tendrán la siguiene leyenda de derechos de autor:

/* Copyright, 1998, Instituto de Ingenieria Electrica */

Recomendación: una función no ocupará más de 2 páginas.
Cuando una función ocupe más de dos páginas, debe considerarse su separación en varias funciones, o colocar las subfunciones en módulos separados. Funciones cortas y relacionadas pueden estar en un mismo archivo.

Norma: largo de línea <= 80 caracteres.
Las líneas de código no deben exceder de 80 caracteres. Las líneas largas deben ser separadas en varios renglones, de modo que al imprimir el código resulte legible. Se recomienda que las líneas de continuación sean indentadas. El largo de línea incluye espacios al principio y comentarios en la misma línea del código.

Norma: Orden de las secciones.
El orden de las secciones de un programa es el siguiente:

Archivos de encabezados.

Recomendación: organización de archivos de encabezado.
Todas las funciones en un mismo archivo de encabezado deben estar relacionadas a una misma función general. Dentro de un archivo de encabezado, la funciones que realicen tareas relacionadas deben estar agrupadas en una misma sección.

Recomendación: nombres de los archivos de encabezado.
Evitar nombres de archivos privados de encabezado que coincidan con nombres de archivos públicos de encabezado. No usar nombes absolutos para archivos de encabezado; colocarlos en su ubicación estándar o en el directorio corriente. La opción de compilación relativa a inclusión de bibliotecas ("include-path") es la mejor forma de manejar bibliotecas privadas extensas.

Norma: archivo de encabezado en el archivo de definición de la función.
Los archivos de encabezado que declaran funciones o variables externas deben incluírse en el archivo que define la función o la variable para permitir verificación de tipos.

Recomendación: no anidar archivos de encabezado.
Los archivos de encabezado no deben anidarse. El prólogo de cada archivo de encabezado debe describir que otros archivos de encabezado deben incluírse para que el actual archivode encabezado funcione. En casos extremos pueden incluírse todas las sentencias de inclusión comunes en un nuevo archivo de inclusión.

4. Declaraciones de variables.

Norma: nombres de variables.
Todas las variables deben comenzar con letra minúscula. En los nombres compuestos por varias palabras, cada palabra excepto la primera deben comenzar com nayúscula, así: una_Variable.
Los nombres de punteros deben empezar con "p_", así: p_UnaVariable.
Los nombres de variables globales deben comenzar por "g_", así: g_UnaVariable.
Los nombres definidos deben ir en mayúsculas separados por subrraya, así:
#define DIAS_SEMANA 7

Recomendación: no usar variables globales.
Se recomienda enfáticamente no usar variables globales. Excepcionalmente, se admite el uso de variables globales para descargar las invocaciones a funciones. Todo uso de variable global dentro de una función debe ser indicado en el prólogo.

Norma: variables globales declaradas al principio del archivo.
Las variables globales deben declararse al principio del archivo, antes de las declaraciones de funciones. Las variables que son globales sólo para las funciones de un mismo archivo deben ser declaradas estáticas.

Norma: variables globales al principio de la función.
Las variables dentro de una función deben declararse al comienzo de la función

Norma: usar #define para constantes simbólicas.
Todas las cantidades que permanezcan constantes deben nombrarse con #define y escribirse en mayúsculas, así:
#define MAX_CANALES 4096
Las constantes simbólicas que se usen en una única unidad de compilación deben definirse al principio de esa unidad de compilación. Las constantes simbólicas de alcance más general deben definirse y documentarse en archivos de encabezado de alcance adecuado.

Norma: declaración explícita de +1 en largo de cadenas para '\0'.
El largo de arreglos de caracteres usados como cadenas y terminados por un caracter nulo, deben definir su largo indicando explícitamente el "+1" para el carater nulo de terminación.
#define LARGO_NOMBRE 20 + 1

Norma: declaración de estructuras.
Cada campo de una estructura debe declararse en un renglón separado. La estructura debe tener un nombre en mayúsculas. La asignacion de una estructura a una variable debe hacerse en una sentencia separada, así:

Recomendación: macros.
Los nombres de macros deben escribirse en mayúsculas. Incluír un comentario en el mismo renglón de declaración de la macro. Las definiciones de macros deben estar al principio del archivo, o en un archivo de encabezado. Colocar paréntesis en torno a los parámetros en el texto de reemplazo, y en torno a todo el texto si es posible, así:
#define SIGUIENTE(p) ((p)->_next)

5. Funciones.

Declaración de funciones.

Norma: valor de retorno declarados explícitamente.
La función debe devolver "void" si no se devuelve ningún valor.

Norma: lista de parámetros.
Si la lista de parámetros no cabe en un renglón, los renglones de continuación deben estar indentados hasta el lugar donde comienza la lista de parámetros en el primer renglón.
Una función que devuelve información por vía de sus parámetros debe devolver en su nombre solamente información de estado.
Cada parámetro pasado a una función debe ocupar un renglón separado en la declaración de la función, seguido de un corto comentario que describa su función.

Norma: función estática.
Toda función que sólo sea llamada desde otras funciones en el mismo archivo debe ser declarada estática.

Patrón para declaración de funciones.

Norma: cuerpo de la función.
La llave de apertura "{" del cuerpo de la función debe estar a la izquierda en un renglón separado o al final del renglón que introduce el bloque. El resto de la función hasta la llave de cierre "}" debe estar indentada un paso.Un paso de indentación es 2 o 3 espacios; no usar tabuladores.
En la función debe haber una única sentencia return con un parámetro si la función no es void. Aún si la función no devuelve ningún valor, es buena práctica incluir una sentencia return.
La llave de cierre "}" debe estar a la izquierda y en un renglón separado.

Norma: prototipo de la función.
Deben crearse prototipos para todas las funciones. Si los prototipos de las funciones residen en un archivo separado, este archivo debe tener extensión ".fp".

6. Comentarios.

Recomendación: patrón para encabezado de archivos y funciones.
Si el archivo contiene funciones relacionadas de tal modo que la modificación de una requerirá probablemente la modificación de varias de las otras, se colocará al principio del archivo el siguiente encabezado, y al principio de cada función un comentario breve que la describa.

/*=================================================================
| Archivo: nombre de archivo
| Propósito: 
| Documentación: (si corresponde)
|
| Revisiones:
| Fecha    Nombre          Revisión
| -------- --------------- ----------------------------------------
| 02-03-98 Juan Perez      Creado
|
===================================================================*/

Si las funciones del archivo no están particularmente relacionadas, se colocará el siguiente encabezado al principio de cada función.

/*=================================================================
| Función: nombre de función
| Propósito: 
| Método: (si corresponde)
|
| Revisiones:
| Fecha    Nombre          Revisión
| -------- --------------- ----------------------------------------
| 02-03-98 Juan Perez      Creado
|
===================================================================*/

Recomendación: comentarios en las funciones.
Los comentarios dentro del cuerpo de las funciones deben restringirse a bloques de comentario que precedan bloques cohesivos. Describirán los propósitos del bloque en el cumplimiento de una tarea cohesiva. El uso de nombres significativos en variables y funciones minimizan la necesidad de comentarios.

Norma: bloques de comentario.
Los bloques de comentario deben estar precedidos y seguidos por un renglón en blanco. En bloques de comentario de varios renglones, los renglones siguientes al primero deben tener un caracter barra vertical "|" al comienzo del renglón. Tal como es requerido, el primer renglón comenzará con "/*" y el último finalizará con "/*". El bloque de comentario debe indentarse al mismo nivel que el bloque de código que comenta.

/*===================================================================
| Este es un ejemplo de bloque de comentario. Nótense las líneas de
| guiones en el primer y último renglón y las barras verticales al
| principio de cada línea de texto. Recuérdese además que deba haber
| un renglón en blanco antes y otro después del bloque de comentario.
=====================================================================*/

7. Sentencias.

Norma: una sentencia por renglón.
Cada sentencia debe ocupar un renglón. "a = 2; b =3;" no es permitido.

Recomendación: no usar sentencias goto ni continue.
Se recomienda enfáticamente no usar sentencias goto ni continue. El uso de break debe limitarse a las sentencias switch, cuando se requiera. Se prefiere el siguiente código

  estado = EXITO;
  i = 0;
  while ((cadena[i] != NULL && (estado == EXITO)) {
    transmitCar(cadena[i], &estado);
  }

en lugar de

  estado = EXITO;
  i = 0;
  while (cadena[i] != NULL) {
    transmitCar(cadena[i], &estado);
  if (estado != EXITO) break;
  }

Recomendación: evitar la sentencia exit.
Se recomienda evitar el uso de la sentencia exit, excepto para el manejo de errores.

Recomendación: máximo 4 niveles de anidamiento en estructuras de control.
El anidamiento de sentencias if, for, while, etc., no debe superar los 4 niveles. Si se requieren más deberá considerarse el uso de una función en alguno de los niveles superiores.

Norma: sentencias nulas.
Las sentencias nulas requieren comentario.Por ejemplo, si el caso default de una sentencia case no hace nada, colocar igualmente el rótulo default y un comentario tal como
/* no hay acción */
seguido de la sentencia break.
El cuerpo nulo de un for o un while debe estar en un renglón separado y contener un comentario que asegure que el cuerpo es intencionalmente nulo, así

while (*destino++, *origen++)
  ; /* vacío */

Norma: comentario para falta de break en switch.
Cuando se pretende que un caso de una sentencia case caiga en el siguiente caso, la falta de break en la sentencia anterior debe ser notada con un comentario.

  switch (queIsotopo) {
    case PU239:    /* misma acción que PU240, sin break */
    case PU240:
      procesoPlutonio();
      break;
    default:
      break; /* si no es PU239 ni PU240 no hay acción */
  }

Norma: bloques de sentencias.
La llave de apertura "{" de los bloques de código debe estar al final de la sentencia de control del bloque o a renglón seguido alineado con la primera letra de la setnencia de control. El cuerpo del bloque debe estar indentado un paso desde la sentencia de control. La llave de cierre "}" debe estar en renglón aparte con la misma indentación que la sentencia de contro. Por ejemplo:

  if(primero < ultimo) {
    resultUno = primero / 2;
    resultDos = ultimo / 2;
  }
  else {
    resultUno = ultimo / 2;
    resultDos = primero /2;
  }
  do
  {
    estado = haceAlgo();
  } while (estado == EXITO);

Recomendación: bloque con sentencia única.
Se aconseja encerrar entre llaves "{...}" aún las sentencias únicas de las sentencias de control:

if (unaCondicion == CIERTO) {

variable Uno = variableDOS;

}

Norma: operadores decremento e incremento sólo en sufijo.
Usar los operadores de incremento "++" y decremento "--" sólo como sufijo, y no como parte de otra sentencia. Se prefiere esta forma

  while (cadena[i] != NULL) {
    haceAlgo();
    i++;
  }

en lugar de

  while (cadena[i++] != NULL) {
    haceAlgo();
  }

Norma: desvío en llamado a función.
Cuando un desvío se base en el resultado de un llamado a función, el llamado a función debe estar un renglón aparte. La forma

  p_FileHandle = fopen("unArchivo", READ_ONLY);
  if (p_FileHandle == NULL) {
    printf("No pudo abrirse archivo; fin de programa");
    terminaAplicacion()
  }
  else {
    haceAlgo();
  }

resulta más fácil de entender que

  if ((fileHandle = open("unArchivo", READ_ONLY)) == NULL) {
    printf("No pudo abrirse archivo; fin de programa");
    terminaAplicacion()
  }
  else {
    haceAlgo();
  }

Norma: evitar efectos secundarios.
Las expresiones no deben producir internamente efectos secundarios. Evitar sentencias tales como while (cadena[i++] != 0).

Norma: no usar el valor verdadero por defecto en las pruebas.
No usar el valo no nulo por defecto. Usar comparaciones explícitas aún si el valor de comparación no cambia nunca. La forma

  if (func() != FALSO)

es preferible a

  if (func())

8. Operadores.

Norma: usar espacios entre operadores binarios.
Todos los operadores que tomen dos parámetros deben tener un espacio antes y otro después del operador.

Norma: no poner espacio después de un operador unario.
No debe haber espacio que separe un operador unario del objeto afectado.

Recomendación: evitar el uso del operador de comparación condicional.
Se recomienda evitar el uso del comparador condicional ternario "?"; se lo permite en macros.

  if (abc > xyz) {
    zUno = abc;
  }
  else {
    zUno = xyz;
  }

es más fácil de leer que

  zUno = (abc > xyz) ? abc : xyz

Norma: usar paréntesis para evitar ambigüedades de precedencia.
Deben usarse paréntesis para eliminar ambigüedades que puedan surgir por desconocimiento de la precedencia de operadores. Por ejemplo, al incrementar la variable apuntada por el puntero p_NumVeces, escribir (*p_NumVeces)++ asegura que se está incrementando el contenido de la dirección y no el puntero.

9. Espacios en blanco.

Recomendación: uso de espacios en blanco para mejorar la legilibilidad.
Usar a discreción los espacios en blanco horizontales y verticales para hacer más legible el código. Los renglones en blanco y la indentación deben reflejar la estructura de bloques del código.

Norma: operadores condicionales en renglones separados.
Una lista de varios operadores condicionales debe separarse en renglones diferentes. El código

  if (nodo->sigte == NULL && totalCuenta < pedido 
     && pedido <= MAXLOTE && servActivo(esteIngreso)) {
   ... 

se escribe mejor así:

  if (nodo->sigte == NULL
     && totalCuenta < pedido 
     && pedido <= MAXLOTE
     && servActivo(esteIngreso))
     {
     ... 

Análogamene, los lazos for complicados deben separarse en líneas diferentes:

  for (corr = *listp, rastro = pList;
      corr != NULL;
      rastro = &(corr->sigte), corr = corr->sigte) {
    haceAlgo();
    haceOtraCosa();
  }

Norma: espaciado de paréntesis.
Las palabras claves seguidas de expresiones entre paréntesis no deben quedar separadas del paréntesis izquierdo de la expresión. Debe colocarse un espacio después de la coma en las listas de argumentos.

10. Constantes.

Norma: nombres de constantes simbólicas en mayúscula.
Las constantes simbólicas deben escribirse en mayúscula. Por ejemplo, CIERTO.

Recomendación: consistencia en la definición de constantes.
Las constantes deben definirse en forma consistente con su uso; por ejemplo, escribir 540.0 en lugar de asumir una conversión forzada de 540.

11. Compilación condicional.

La compilación condicional sólo debe usarse para controlar la compilación de código dependiente de máquina, fijando opciones de tiempo de compilación, o para depuración.

Norma: compilación condicional por defecto.
La compilación condicional de código dependiente de máquina debe llevar, por defecto, a error. La compilación condicional de código destinado a optimización debe llevar, por defecto, a código no optimizado.

Recomendación: compilación condicional.
Siempre que sea posible, colocar el código de compilación condicional en un archivo de encabezado en lugar de en el programa principal. Las unidades de compilación condicional deben encerrarse entre llaves de a una característica.

12. Portabilidad.

Norma: código de máquina en un archivo separado.
Colocar todo el código de máquina en un archivo separado del código independiente de máquina. El código dependiente de máquina debe estar puesto con #ifdef para que salga un mensaje de error significativo si el código es compilado en una máquina diferente.

Recomendación: uso del código de máquina.
El código de máquina debe usarse solamente cuando sea estrictamente necesario. Intentar escribir como independientes de máquina todas las rutinas que soporten código dependiente de máquina.

Recomendaciones generales para la portabilidad.
Recordar que los largos de los tipos nativos puede variar entre plataformas, especialmente punteros y enteros. La presición y formato de almacenamiento del tipo float también puede variar entre plataformas.
No asumir que el programa será siempre ejecutado en la máquina para la cual fue diseñado originalmente.

13. ANSI C.

 Norma: código compatible ANSI.
Todo el código debe conformar el estándar de ANSI para lenguaje C.

14. Varios.

Norma: verificar siempre el valor de retorno de las funciones.
Verificar siempre el valor de retorno de las funciones que devuelven valores especiales en caso de error.

Recomendación: usar funciones de biblioteca siempre que sea posible.
Usar funciones de biblioteca siempre que sea posible. No reinventar la rueda.

15. Conclusión.

Las recomendaciones y normas expuestas en esta guía deben seguirse de buena fé, recordando que siempre se está trabajando, aunque sea potencialmente, en un grupo de trabajo.

16. Referencias.

Volver al Principio