GUÍA DE ESTILO PARA C

Juan José Moreno Moll
version 3.0
6 de Marzo de 1997



Guía de estilo para C

Juan José Moreno Moll
version 3.0
6 de Marzo de 1997


1. Introducción

1.1 Finalidad

Este documento tiene como finalidad proporcionar un conjunto de reglas que nos ayuden a escribir programas en C con un "buen estilo". Un código escrito con buen estilo es aquel que tiene las siguientes propiedades:

- Está organizado.

- Es fácil de leer.

- Es fácil de comprender.

- Es fácil de mantener.

- Es fácil detectar errores en él.

- Es eficiente.

En resumen, escribir programas siguiendo un estilo sirve para tener programas fáciles de leer, fáciles de modificar, evitar algunos errores y para facilitar la búsqueda de otros errores.

IMPORTANTE: Se puede escribir un código con las características anteriores con muchos estilos, de los que éste es uno más.

Otra utilidad que tiene seguir un estilo concreto para un grupo de personas que desarrollan juntas programas, es que todo el código escrito por cualquier persona del grupo tiene el mismo formato. Por lo que el código realizado por una persona del grupo es mucho más comprensible para otra persona del mismo grupo. Ayuda a trabajar en grupo. Por eso es muy importante que, una vez un grupo de personas elige un estilo concreto para escribir código, no debe cambiarlo hasta terminar el trabajo que realizan conjuntamente.

Por esta razón, aunque hay otros estilos tan buenos como éste, nosotros siempre seguiremos las reglas de este documento.

1.2 Personas a que va dirigido y requisitos

Este documento va dirigido a los alumnos de la asignatura del Laboratorio de Programación II de la Ingeniería Informática. Todas las prácticas realizadas en este laboratorio deben estar escritas siguiendo este documento. Este documento va dirigido a personas que conocen el lenguaje C. No es una guía de aprendizaje de C.

1.3 Contenido del documento

Este documento contiene una guía para organizar el contenido de programas, ficheros, y funciones en C. Se indica estructura y lugar donde se colocan variables, instrucciones, y comentarios.

Este documento está basado en una guía de estilo utilizada en el "Software Engineering Laboratory", de la NASA.

2 Facilitar la lectura y el mantenimiento del código

Los principios de esta sección sirven para aumentar la legibilidad del código y para facilitar el mantenimiento del código. Son:

- Organizar programas utilizando técnicas para encapsular y ocultar información.

- Aumentar la legibilidad usando los espacios y líneas en blanco.

- Añadir comentarios para ayudar a otras personas a entender el programa.

- Crear nombres que ayuden a entender el programa.

- Seguir el estándar ANSI C, cuando sea posible.

2.1 Encapsulación y ocultación de información.

La encapsulación y ocultación de información ayudan a organizar mejor el código y para evitar el acoplamiento entre funciones del código.

Encapsulación: Permite agrupar elementos del programa. La encapsulación se puede hacer en muchos niveles:

- Un programa se organiza en ficheros, usando ficheros de cabecera.

- Un fichero se organiza en una sección de datos y una sección funciones.

- Las funciones con una cierta relación se agrupan en ficheros individuales.

- Los datos se organizan en grupos lógicos (estructuras de datos).

Ocultación de información: controla el alcance de los elementos del programa (datos o funciones). Se deben utilizar las construcciones que proporciona C para controlar el alcance de las funciones y variables del programa. De esta forma de evitan acoplamientos no deseados entre diferentes partes del código del programa. Debemos seguir las siguientes reglas:

- La información sobre funciones y variables de un fichero de escribe en ficheros de cabecera, que se incluyen solo allí donde son necesarios.

- Debemos utilizar los conceptos de variable externa para poder acceder a variables contenidas en otros ficheros. Y utilizar el concepto de variable o función estática de un fichero para limitar el acceso de funciones de otros ficheros.

2.2 Espacios en blanco

Los espacios en blanco facilitan la lectura y el mantenimiento de los programas. Los espacio en blanco que podemos utilizar son: líneas en blanco, carácter espacio, sangrado.

Línea en blanco:

Se utiliza para separar "párrafos " o secciones. Cuando leemos un programa entendemos que un fragmento de código entre dos líneas en blanco forma un conjunto con una cierta relación lógica. Como separar secciones o párrafos en el programa:

- Las secciones que forman un fichero se separan con al menos una línea en blanco. Secciones que forman un fichero: Sección de comentario, sección de "#includes", sección de "#defines", sección de variables, sección de funciones.

- Dentro de una función se separan con una línea en blanco las secciones de variables y la del código de la función.

- Dentro de una función se separan con una línea en blanco los fragmentos de instrucciones muy relacionadas entre sí (por ejemplo, conjunto de instrucciones que realizan una operación).

Ejemplo:

#define LOWER 0
#define UPPER 300
#define STEP 20

main() /* Fahrenheit-Celsius table */ { int fahr; for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP) printf("%4d %6.1f\n", fahr, (5.0/9.0)*(fahr - 32)); }

Espacio en blanco:

Los espacios en blanco sirven para facilitar la lectura de los elementos que forman una expresión. Los espacios en blanco se utilizan en los casos siguientes:

- Las variables y los operadores de una expresión deben estar separados por un elemento en blanco.

- Las lista de definición de variables, y las listas de parámetros de una función se deben separar por un espacio en blanco.

Ejemplos:

Espaciado correcto:

 *average  =  *total  /  *count;         /* compute the average */

Espaciado incorrecto, que además da un error:

 *average=*total/*count;                 /* compute the average */
                 ^ Comienzo del comentario y fin del comentario ^

Espaciado dentro de una lista de parámetros:

 concat(s1, s2)

Sangrado:

El sangrado se utiliza para mostrar la estructura lógica del código. El sangrado óptimo es el formado por cuatro espacios. Es un compromiso entre una estructuración legible y la posibilidad de que alguna línea (con varios sangrados) del código supere el ancho de una línea de una hoja de papel o del monitor.

Ejemplo: Sangrado a 4 espacios.

main()
{
    int c;

    c = getchar();
    while (c!= EOF)
    {
         putchar(c);
         c = getchar();
    }
}

2.3 Comentarios

Los comentarios dan información sobre lo que hace el código en el caso que no sea fácil comprenderlo con una lectura rápida. Los comentario deben dar información adicional al lector. Se usan para añadir información o para aclarar secciones de código. No se usan para describir el programa instrucción a instrucción. Por lo tanto no se deben poner comentarios a una sola instrucción. Los comentarios se añaden en los niveles siguientes:

- Comentarios del programa: Siempre se debe incluir con los ficheros del programa un fichero LEEME que da una descripción de programa y explica como está organizado.

- Comentario a ficheros: Al comienzo de cada fichero se añade un prólogo del fichero que explica el propósito del fichero y da otra información (ver sección 4).

- Comentarios a funciones: Al comienzo de cada función se añade un prólogo de la función que explica el propósito del función (ver sección 5).

- Comentarios dentro del código: Estos comentarios se añaden junto a la definición de algunas variables (las más importantes), para explicar su propósito, y al comienzo de algunas secciones de código especialmente complicadas, para explicar que hacen.

Los comentarios se pueden escribir en diferentes estilos dependiendo de su longitud y su propósito. En cualquier caso como reglas generales:

- Los comentarios en general se escriben en líneas que no contienen código y antes del código que queremos clarificar. Esta regla se aplica siempre si el comentario tiene más de una línea.

- Solo en dos casos se permite poner en la misma línea un comentario y una instrucción: comentarios a una definición de variable, que explica la finalidad de esta variable. Y comentario para indicar final de un bucle.

Aquí vamos a describir como hacer comentarios dentro del código. Dentro de este tipo de comentarios se pueden distinguir:

- Comentarios en cajas: Usados para prólogos o para separar secciones.

- Separador de secciones: Son líneasque sirven para separar secciones, funciones, etc.

- Comentarios para bloques grandes: Se usan al comienzo de bloques de código grandes para describir esa porción de código.

- Comentarios cortos: Se usan para describir datos y casi siempre se escriben en la misma línea donde se define el dato.

- Comentarios para bloques pequeños: Se escriben para comentar bloques de instrucciones pequeños. Se colocan antes del bloque que comentar y a la misma altura de sangrado.

Comentarios en cajas:

Los prólogos usados para comentar funciones o ficheros se explican más adelante en otros secciones. Estos tipo de comentarios también se puede usar para separar dentro de un fichero secciones de datos de secciones de funciones, para separar grupos de funciones y para comentarios muy importantes.

Ejemplo: comentario tipo prólogo en una caja:

/**********************************************************
 *       FICHERO: Nombre                                  *
 *                                                        *
 *      PROPOSITO:                                        *
 *                                                        *
 **********************************************************
Separador de secciones:

Ejemplo: Separador de secciones.

/**********************************************************/
Comentarios para bloques grandes:

Ejemplo: comentarios para bloques grandes de código.

/*
 *       Los cometarios se escriben a partir de aquí. Usar para comentarios a
 *      más de una sentencia.
 */

Comentarios cortos:

En caso de utilizar este tipo de comentario, seguir las siguientes reglas:

- Utilizar uno o más tabuladores para separar la instrucción y el comentario.

- Si aparece más de un comentario en un bloque de código o datos, todos comienzan y terminan a la misma altura de tabulación.

Ejemplo: Comentarios en un bloque de datos.

double  ieee_r[];        /* array of IEEE real*8 values */
unsigned char ibm_r[];   /* string of IBM real*8 values */
int count;               /* number of real*8 values     */
Comentarios para bloques pequeños:

Ejemplo:

switch (ref_type)
{
    /* Perform case for either s/c position or velocity * vector request using
       the RSL routine c_calpvs */

    case 1:
    case 2:
    ...
    case n:
}
Ejemplo: utilización de comentarios grandes frente a la utilización incorrecta de comentarios cortos.

Estilo correcto:

/*
 * Main sequence: get and process all user requests
 */

while (!finish())
{
    inquire();
    process();
}

Estilo no recomendado:

while (!finish())  /* Main sequence:       */
{                  /*                      */
    inquire();     /* Get user request     */
    process();     /* And carry it out     */
}                  /* As long as possible  */

2.4 Elección de nombres. Nombres significativos

Debemos elegir nombres para ficheros, funciones, constantes o variables que sean comprensibles y fácilmente legible. Para elegir nombres podemos seguir las siguientes recomendaciones generales:

- Elegir nombres comprensibles y con relación con el programa.

- Seguir una forma uniforme cuando hagamos abreviaciones de nombres. Por ejemplo si hay un grupo de funciones asociados con "datos de refresco", podiamos usar como prefijo de las funciones "dr_".

- Cuando se hagan abreviaciones utilizar combinaciones de letras que sugieran el nombre completo. Por ejemplo si queremos abreviar "medida de salud" una mala abreviación sería "mesa" y una mejor sería "med_sa".

- El uso del carácter '_' aumenta la legibilidad y la claridad:

   crear_circulo

- Elegir nombres únicos para cada elemento del programa.

- Usar nombre largos aumenta la legibilidad, pero si son muy largos pueden lograr lo contrario y dificulta expresar la estructura del programa mediante el sangrado.

- Los nombres con más de 4 caracteres deben diferir por lo menos en los dos últimos caracteres. Tambien se puede usar el carcacter '_' para diferenciar nombres similares:

     systst          sys_tst
     sysstst         sys_s_tst

- Los nombres deben ser únicos independientemente de que estos se escriban en mayúsculas y minúsculas, aunque el C distingue entre mayúsculas y minúsculas (no es lo mismo Linea que linea).

- No usar el mismo nombre para variables y para tipos (o estructuras) aunque el C lo permite.

Nombres habituales

Hay algunos nombres cortos que se usan muy habitualmente. El uso de estos nombres es aceptable.

Ejemplo: nombres cortos aceptables:

c            caracteres
i, j, k      indices
n            contadores
p, q         punteros
s            cadenas
Ejemplo: sufijos para variables aceptables.
_ptr         punteros
_file         variables de tipo fichero

Nombres de variables

Los nombres usados por variables de globales no se deben utilizarse estos mismos nombres dentro de las funciones para nombrar variables locales. La duplicación de nombres crea variables ocultas que puede causar que el programa no funcione como deseamos.

Se puede usar el mismo nombre para variables locales de funciones distintas. Sin embargo si se utilizan el mismo nombre para distintas variables locales estas deberían significar en las distintas funciones lo mismo.

Uso de mayúsculas y minúsculas

Para reconocer fácilmente la clase de un identificador se utilizan las siguientes normas de utilización de mayúsculas y minúsculas cuando se construyen nombres:

- Variables: los nombres de las variables se construyen con palabras minúsculas separadas por el carácter '_'.

- Nombres de Funciones: los nombres de las funciones se pueden escribir en dos estilo:

a) Una o más palabras en minúscula separadas por '_'. Sólo si una de las palabras es un nombre propio se admite que la primera letra de una palabra está en mayúscula.

b) Una o más palabras en minúscula excepto la primera letra, que es mayúscula (las demás no). No se usa el carácter '_'.

- Constantes, tipos y identificadores del preprocesador : usan nombres construidos con palabras en mayúsculas separadas por '_'.

3. Organización del programa

Esta es una descripción de la organización del código de un programa en ficheros. Las características de una buena organización del programa en ficheros son: agrupar funciones y estructuras de datos que estén relacionadas lógicamente en un mismo fichero y controlar la visibilidad de los contenidos de estos ficheros. La visibilidad de los ficheros debe ser la mínima imprescindible. Cada módulo debe tener el mínimo número de funciones y de estructuras de datos accesibles desde otros módulos (principio de ocultación de información).

El esquema de organización de un programa en ficheros es el siguiente:

Programa :

   LEEME
   Ficheros de cabecera estándar:    <stdio.h>
                                     <math.h>
   Ficheros de cabecera:             "global.h"
                                     "tipos.h"

   Ficheros de programa:      fichero_programa.c
                                   Prólogo del fichero
                                   Instrucciones de operación y uso
                                   'Includes' de ficheros de cabecera
                                   Definiciones y declaraciones externas
                                   Funciones:
                                        Prólogo de la función
                                        Parámetros de la función
                                        Declaraciones y definicieones externas
                                        Código:
                                               Operadores
                                               Expresiones
                                   Más datos externos
                                   Más funciones
    Módulos fuente:           módulo.c 
    Utilidades para compilar: Makefile

3.1 Fichero de programa

Un programa en C consiste en uno o más ficheros uno de los cuáles contiene a la función main() . La función main() se encarga de lanzar a las demás funciones del programa.

Cuando el programa es suficientemete grande deberiamos separarlo en varios ficheros y usar las técnicas de encapsulación y ocultación de datos para agrupar funciones y estructuras de datos relacionadas lógicamente en un mismo fichero. Los ficheros del programa se deben organizar como sigue:

* Crear un fichero LEEME que indica que hace el programa.

* Agrupar la función main() con otras funciones relacionadas logicamente con ella en el fichero de programa.

* Usar los ficheros módulos fuente para agrupar otras funciones relacionadas lógicamente .

* Usar los ficheros de cabecera para encapsular las definiciones y declaraciones de variables y funciones.

* Escribir un fichero Makefile para recompilar de forma más eficiente.

3.2 Fichero LEEME

El fichero LEEME se utiliza para explicar que hace el programacomo se utiliza, como está organizado (ficheros que lo componen) y una documentación general del programa. Un fichero LEEME debería incluir:

* Todas las marcas de compilación condicinal y su significado.

* Ficheros que dependen de una cierta máquina, plataforma o compilador concreto.

* Directorios de componentes reutilizados (módulos de otros programas utilizados).

3.3 Librerías estándar

Las librerías estándar son conjuntos de funciones dentro de un fichero que generalmente no hemos hecho nosotros. Cuando nuestro programa usa alguna de estas funciones debemos incluir los ficheros de cabecera correspondiente (por ejemplo: stdio.h, math.h).

3.4 Archivos de cabecera

En los archivos de cabecera se incluyen constantes, tipos, protopipos, macros etc. y están relacionadas como una librería o módulo fuente. Se utilizan como una técnica para encapsular y limitar la visibilidad que el resto del programa tiene sobre las funciones de una librería o módulo fuente. Para utilizar una función solo nos debería hacer falta la información que le archivo de cabecera contiene sobre ella.

Los ficheros de cabecera se incluyen al comienzo de los ficheros fuente de C. Algunos están definidos en el propio C y otros pueden ser construidos por el programador.

Características de los archivos de cabecera y reglas para su utilización y construcción:

* Usar #include <cabeceras de sistema> para cabeceras del sistema.

* Usar #include "cabeceras propias" para cabeceras construidas por el programador.

* Los ficheros de cabecera contienen: definiciones de datos, prototipos, typedefs, tipos enumerados, macros uqe pueden ser usados por el programa.

* Archivos de cabecera se organizan por funciones.

* Las declaraciones, tipos, etc que se utilizan en sistemas distintos se colocan en archivos de cabecera distintos (se entiende por sistemas plataformas, sistemas operativos, compiladores, etc.).

* Si un conjunto de declaraciones es probable que deben cambiarse al portar el código a otra plataforma distinta colocar estas declaraciones en un archivo de cabecera distinto.

* Evitar nombres que ya usan los archivos de cabecera estándar (por ejemplo stdio.h, math.h, etc.)

* Los archivos de cabecera que declaran funciones y variables siempre se deben incluirse en el módulo fuente donde estás funciones y variables están definidas.

* Usar de forma explicita todos los archivos de cabecera que hagan falta en cada programa a pesar de que puedan estar anidados y contenidos dentro de otros archivos de cabecera.

* En el prólogo del archivo de cabecera se debe indicar que otros archivos de cabecera necesita utilizar.

3.5 Módulos fuente

Contiene un conjunto de funciones, constantes, variables etc. que tienen una cierta relación. Son similares al fichero de programa excepto en que no tienen a la función main().

3.6 Makefile

Se usan para facilitar la comilación y el enlazado del programa. En un makefile se indica siempre:

* Lista de todos los módulos que forman parte del programa.

* Indica que ficheros son parte de una librería.

* Indica dependencias entre ficheros. Por ejemplo entre módulos fuente y sus respectivos archivos de cabecera.

3.7 Extensiones de ficheros habituales

Una forma de indicar la clase decada fichero es su extensión. Una lista de extensiones de ficheros con lo que deberían significar esta extensión es la siguiente:
Tipo de fichero                                 Extensión

Fichero fuente C                                .c
Fichero fuente ensamblador                      .s
Fichero objeto                                  .o
Archivo de cabecera                             .h
Fichero fuente de YACC                          .y
Fichero fuente de LEX                           .l
Fichero de salida                               .out
Makefiles                                       .mak

4. Organización de un fichero

La organización del un fichero es tan importante para la legibilidad y el mantenimiento de un programa como la organización del programa en ficheros. El esquema de organización de un fichero es el siguiente:
   Prólogo del fichero
   Utilidad e instrucciones de uso en el caso de un fichero de programa
   Archivos de cabecera en este orden:
      #include <stdio.h> ( y <stdlib.h>)
      #include <otras cabeceras del sistema>
      #include "cabeceras de usuario"
      Defines, typedefs, macros, etc. que usa el fichero
   Declaración externa de datos usados por el fichero
      declaración externa de variables definidas en otros ficheros
      definiciones no estáticas usadas en este fichero

   Funciones
      prologo de la función
      cuerpo de la función

   Más declaraciones externas de datos usados por el fichero

   Más funciones

4.1 Prólogo de un fichero

Este prólogo indica el contenido del fichero, su utilización, etc.

Los ficheros fuentes deben contener un prólogo como el siguiente:

/************************************************************
 *  NOMBRE de FICHERO:                                      *
 *                                                          *
 * PROPÓSITO:                                               *
 *                                                          *
 * REFERENCIAS A FICHEROS :                                 *
 * Nombre                        E/S      Descripción       *
 *                                                          *
 *  VARIABLES GLOBALES:                                     *
 * Nombre                tipo     E/S      Descripción      *
 *                                                          *
 *  VARIABLES EXTERNAS:                                     *
 *  fuente: <         >                                     *
 * Nombre                tipo     E/S      Descripción      *
 *                                                          *
 *  REFERENCIAS  EXTERNAS:                                  *
 * Nombre                                Descripción        *
 *                                                          *
 * CONDICIONES de TERMINACIÓN ANORMAL y MENSAJES ERROR y    *
 * ADVERTENCIA:                                             *
 *                                                          *
 * SUPOSICIONES, RESTRICCIONES:                             *
 *                                                          *
 * NOTAS:                                                   *
 *                                                          *
 * REFERENCIAS A ESPECIFICACIÓN/DISEÑO:                     *
 *                                                          *
 * HISTORIA DE DESARROLLO:                                  *
 * Fecha  Autor  Id Cambio  Versión  Descripción del Cambio *
 *                                                          *
 ************************************************************/
 

Descripción de los campos:

En los archivos de cabecera el prólogo debe ser:

/************************************************************
 * NOMBRE de FICHERO:                                      *
 *                                                          *
 * PROPÓSITO:                                               *
 *                                                          *
 * VARIABLES GLOBALES:                                     *
 * Nombre                tipo     E/S      Descripción      *
 *                                                          *
 * HISTORIA DE DESARROLLO:                                  *
 * Fecha  Autor  Id Cambio  Versión  Descripción del Cambio *
 *                                                          *
 ************************************************************/

Hemos descrito la forma general para escribir código en módulos fuente y archivos de cabecera. Recomendaciones para escribir módulos fuente y archivos de cabecera. Estas recomendaciones pueden servir de ayuda para escribir código, pero se pueden seguir o no según la conveniencia de cada caso:

Ejemplo de módulo fuente y su correspondiente archivo de cabecera:

módulo fuente: módulo.c.

/***********************************************************
 *                                                         *
 *               Prólogo de modulo.c                       *
 *                                                         *
 ***********************************************************/


#define _MODULO_C_

#include <stdio.h>      /* archivos de cabecera del sistema             */
...

#include "cabecera.h" /* archivos de cabecera propios */ ...

/* Variables globales */ int opcion; char cadena[200]; ...

/* Variables estáticas */ stactic char tabla; ...

/* Funciones estáticas */ /* Prólogo de la función f1() */ static f1(int, ... ) { ...

} /* Prólogo de la función f1() */ static f2(int, ...) { ...

} ...

/* Funciones */ /* Prólogo de la función fa() */ fa(int, ...) { ...

} /* Prólogo de la función fb() */ fb(int, ...) { ... } ...

archivo de cabecera: cabecera.h.

/***********************************************************
 *                                                         *
 *                Prólogo de cabecera.h                     *
 *                                                         *
 ***********************************************************/

#include <stdio.h>                /*  archivos de cabecera del sistema    */
...

#include "... .h" /* archivos de cabecera propios */ #ifndef _CABECERA_H_

#define _CABECERA_H_ #ifdef _MODULO_C_ /* Prototipos de funciones estáticas */ static f1(int, ... ); static f2(int, ...); ...

#endif /* Declaración externa de variables globales */ extern int opcion; extern char cadena[200]; ...

/* Prototipos de funciones */ fa(int, ...); fb(int, ...); ...

4.2 Directiva include

La directiva #include se utiliza para indicar como son las funciones, tipos, cts. etc. que se usan en un archivo. Normas de utilización de directiva .#include:

4.3 Defines y typedefs

Después de los #includes se colocan #defines, typedef, macros etc. que necesita el fichero en el caso de que no se hayan colocado ya en un archivo de cabecera(que el lo habitual). El orden colocar esta parte del fichero es:

4.4 Declaraciones y definiciones de datos externos

En esta sección se declaran variables externas de otros módulos para hacerlas visibles en nuestro fichero en el caso de que estas declaraciones externas no están dentro de un archivo de cabecera (que es lo habitual).

4.5 Secuencia de funciones

Vamos a hacer la descripción de la organización externa de las funciones. La sección siguiente (sec. 5.) tiene una descripción completa de la organización interna de una función. Las normas para colocar las funciones en un fichero son:

Ejemplo de separación de funciones:
/************************************************************/

prologo de main()
cuerpo de main()

/************************************************************/

prologo de Función1()
cuerpo de Función1()

/************************************************************/

prologo de Función2()
cuerpo de Función2()

/************************************************************/

Ejemplo de función con una variable externa:

/************************************************************/

Función1()

/************************************************************/

/* La siguiente variable está disponible para la función    *
 *  Función1 pero no para la función Función2               */

extern int opcion;

/************************************************************/

prologo de Función2()

cuerpo de Función2()

/************************************************************/

5. Organización de una función

Esta sección expone las reglas de organización de una función. El esquema general de la organización interna de una función es la siguiente:

5.1 Prólogo de la función

El prólogo de la función contiene información sobre la función. Debe contener:

Ejemplo de prólogo de la función:

/*****************    nombre_funcion()  *******************************
 *  Prototipo:                                                        *
 *                                                                    *
 *  Descripción:                                                      *
 *                                                                    *
 *  Parámetros:                                                       *
 *  Nombre                tipo     E/S              Descripción       *
 *                                                                    *
 * Valor devuelto:                                                    *
 *                                                                    *
 **********************************************************************/

5.2 Nombres de funciones

Estilo para crear nombres de funciones (ver sec. 2.4)

Recomendaciones para poner nombres significativos a las funciones: Ejemplo: frase imperativa.

   obtener_siguiente_cadena
   incrementar_contador_elem
Ejemplo: frase enunciativa

   cabeza_pila
   lector_sensor
Ejemplo: frase imperativa

   pila_esta_vacia
   fichero_existe

5.3 Parámetros de entrada de la función

Ejemplo: declaración de parámetros de entrada.

   int coge_linea(char *cadena,  int long);
   {
      ...

}

5.4 Declaraciones externas

Si una función necesita una declaración externa, ésta se coloca nada más comienza el bloque de código de la función.

Ejemplo: Declaración externa

   char  *guardar_cadena(char *cadena)
   {
       extern  char    *malloc();
       ...

}

5.5 Definición de variables internas

Las variables internas se deben colocar después de la declaración de variables externas. Reglas para organizar el bloque de definiciones de variables internas:

5.6 Estructura del bloque de instrucciones de una función

Las reglas que debemos seguir son:

Ejemplo:

    char *copia_cadena(char *cad)
    {
        char *ptr;    /* puntero a  memoria donde se copia contenido de `cad'*/

        ptr = (char *) malloc(strlen(string) + 1);
        if (ptr != (char *) NULL)
            strcpy(ptr, string);
        return(ptr);
    }

5.7 Instrucción return

Recomendaciones para usar la instrucción return:

Ejemplo: Función con único return. Recomendado.

    encontrado = FALSE;
    for(i = 0; (i < max) && (!encontrado); i++)
        if ( vetc[i]  ==  tecla)
            encontrado  =  CIERTO;
    return (encontrado);
Ejemplo: Función con varios return. No recomendado.

    for(i = 0; (i < max) ; i++)
        if ( vetc[i]  ==  tecla)
            return( CIERTO);
    return (FALSE);

6. Expresiones , operadores y tipos de datos

En esta sección se enumeran:

Algunas reglas generales que se pueden seguir son:

6.1 Variables

Cuando se definan variables del mismo tipo colocar una por línea a menos que su nombre sea suficientemente claro o sean variables auxiliares (contadores de bucles for, por ejemplo):

    int año,  mes,  día;
Si se quiere agrupar variables relacionadas, colocar las variables relacionadas del mismo tipo en una línea, separadas por comas y un carácter en blanco:

    float   x,  y,  z;
    int año,  mes,  día;
Un ejemplo de como añadir un breve comentario a una variable:

    int x;               /*  Comentario */
    int y;               /*  Comentario */

6.2 Constantes

Las constantes siempre se escriben en mayúsculas. En ANSI C hay varias formas de especificar constantes: con el modificador conts , con el comando del preprocesador #define y con tipo de datos enumeración.

Modificador conts

Las constantes definidas con este modificador deben escribirse en mayúsculas.

#define

Esta directiva sirve para sustituir identificadores por una cadena. Entre otras cosas, se utiliza para tener nombres significativos que se refieren a constantes numéricas de código hard:

    #define   NULL    0
    #define   FCAD    '\0'
No debe usarse para referirse a constantes que sean una expresión, ya que puede dar problemas. Para definir constantes que sean expresiones usar el modificador conts.

Tipos enumerados

El tipo enumerado crea una asociación entre nombres cts. y sus valores. Dentro del tipo enum los nombres se colocan en la misma columna. El ejemplo siguiente asocia los valores 0, 1, 2 a las cts. BAJO, MEDIO, ALTO:

enum posicion
{
        BAJO;
        MEDIO;
        ALTO;
}

6.3 Declaraciones y definiciones de variables

Números

Formas de escribir valores cts. numéricos:

Números en coma flotante: deben tener al menos un número después del punto decimal:

     0.5     5.0     1.0e+33
Números en hexadecimal: Comienzan con '0x' y pueden usar las letras (en mayúsculas) 'A' a 'F':

     0x123   0xFFF
Números 'long': terminan con la letra mayúscula 'L':

     123L    5.0L    1.3e+100L

Estructuras

Las estructuras se utilizan para agrupar información heterogénea en un solo bloque.

Usar typedef para asignar un nombre a las estructuras.

Variables automáticas (locales)

La inicialización de las variables se puede hacer en el mismo momento de la definición o cuando se van a usar. Es mejor inicializar la variable en el momento en el que se va a usar, sobre todo si la utilizamos muchas hojas de código después de su definición:
Ejemplo: variable inicializada cuando se declara. No recomendado.

    int max = 0;
    ...

/* Utilizada varias páginas después */ ...

for (i=0; i<n; i++) if (vec[i] > max) max = vec[i];

Ejemplo: variable inicializada cuando se usa. Recomendado.

    int max;
    ...

/* Utilizada varias páginas después */ ... max = 0;

for (i=0 ; i<n ; i++) if (vec[i] > max) max = vec[i];

6.4 Conversión de tipos

En C cuando en una asignación el tipo de la parte izquierda del asignación y el tipo de la expresión de la parte derecha de la asignación son distintos se produce una conversión conversiones por defecto.

Se deben evitar las conversiones por defecto. Utilizar el operador (cast) para que las conversiones sean explícitas.

Ejemplo: conversión de tipos explícita (recomendada):

    float f;
    int i;
    ... 

f = (int) i;

Ejemplo: conversión de tipos implícita (no recomendada):

    float f;
    int i;
    ... 

f = i;

6.5 Conversión de punteros

Los programas no deben contener conversión de punteros, excepto en los casos:

6.6 Operadores

Las reglas para escribir los operadores:

6.7 Operador asignación dentro de una expresión

El operador asignación se puede usar dentro de otras expresiones, especialmente condicionales. Este uso de la asignación dificulta la compresión del código y no está recomendado:

Ejemplo: asignación dentro de una expresión. No recomendado.

    if  ( (f  = fopen(nombre,  "rb")) !=  NULL)
    {
        ...

}

Ejemplo: asignación fuera de la expresión. Recomendado.

    f = fopen(nombre,  "rb");
    if  (f != NULL)
    {
        ...

}

6.8 Expresión condicional

La expresión condicional ((z = a <b ? a : b ) se puede utilizar en lugar de

    if (a < b)
        z = a;
    else
        z= b;
Este operador se debe utilizar sólo si las expresiones que contiene son simples y fácilmente comprensibles. En otro caso su uso no está recomendado.

7. Instrucciones y control de flujo

Esta sección indica como escribir las instrucciones. Las reglas hay descritas indican:

7.1 Secuencia de instrucciones

Aquí describimos como colocar las instrucciones en un bloque.

Colocar instrucciones: Se coloca una instrucción por línea.

Comparaciones: Se deben evitar las comparaciones implícitas.

Comparación implícita. No recomendada.

    if (! (tam % n))
Comparación explícita. Recomendada.

    if  ((tam  % n) == 0)
Bucles infinitos:

Si por alguna razón necesitamos construir un bucle infinito con un bucle for o while el punto y coma se coloca en una línea aparte. Así indicamos que este bucle infinito no es un error y lo hemos construido de forma deliberada:

    while (1)
        ;        /* no hacer nada */
Llaves: { }

Una forma de agrupar instrucciones en bloques es utilizar llaves { }. La forma de colocar llaves que se recomienda es: cada llave en líneas separadas sin ninguna otra instrucción y en la misma columna de la instrucción de la que dependen:

    for (i  =  0;  i  <  strlen(cad); i++)
    {
        cad[i] = vect[i];
        x = x + vect[i];
    }
Aunque algunas veces las llaves no son necesarias, esta pueden ayudar a la legibilidad del código. Se puede incorporar llaves, innecesarias en el código, si esto aumenta la legibilidad del programa.
Si un bloque entre llaves es muy grande es recomendable colocar un comentario en la llave de fin de bloque, que indique donde comienza este bloque:

    if ( marca  == DEFINIDO)
    {
        ... /* Muchas líneas   */

} /* if: marca == DEFINIDO */ else { ... /* Muchas líneas */

} /* else: marca == DEFINIDO */ ...

7.2 Instrucciones

Sección para indicar estilo para escribir las instrucciones en C. Se muestra mediante ejemplos.

if

Sangrado con única instrucción:

    if (expresion)
        una_instrucción;
Sangrado con bloque de instrucciones entre llaves:

    if (expresion)
    {
        instrucción_1;
        ...

instruccion_n; }

if else

Sangrado con única instrucción:

    if (expresion)
        instrucción;
    else
        instrucción;
Sangrado con bloque de instrucciones entre llaves:

    if (expresion)
    {
        instrucción_1;
        ...

instruccion_n; } else { instrucción_1; ...

instruccion_n; }

if else if

Formato:

    if (expresion)
        instrucción;
    else
        if
            instrucción;

switch

Formato:

    switch (expresion)
    {
        case aaa:
            instrucción;
            break;
        case bbb:
            instrucción;
            break;
        ...

default: instrucción; break; }

while

Sangrado con única instrucción:

    while (expresion)
        una_instrucción;
Sangrado con bloque de instrucciones entre llaves:

    while (expresion)
    {
        instrucción_1;
        ...

instruccion_n; }

for

Sangrado con única instrucción:

    for (expresion)
        una_instrucción;
Sangrado con bloque de instrucciones entre llaves:

    for (expresion)
    {
        instrucción_1;
        ...

instruccion_n; }

do while

Sangrado con bloque de instrucciones entre llaves:

    do
    {
        instrucción_1;
        ...

instruccion_n; } while (expresion)

8. Portabilidad y eficiencia

Un código bien escrito debe poder ejecutarse en otras máquinas o plataformas haciendo un mínimo de cambios. Nuestro código debe ser lo más portable posible.

Cuando se escriba código seguir las siguientes reglas para aumentar su portabilidad y su eficiencia:

8.1 Reglas para mejorar la portabilidad

8.2 Reglas para mejorar la eficiencia

9. Código ejemplo

El siguiente ejemplo muestra un programa escrito siguiendo el estilo descrito en este documento. Incluye:

* Un makefile: facilita el proceso de compilación y enlazado del programa.

* Un fichero *.c.

* Un fichero *.h