Está en la página 1de 9

Estándares de Codificación en C

Comentarios
En los archivos de cabecera de cada módulo figurarán obligatoriamente comentarios junto
al prototipo de cada función para la descripción de su finalidad y su utilización. Deberán ser
comentados los significados de cada parámetro, si son de entrada o salida o ambas cosas y
la interpretación de los valores producidos, tanto en los argumentos de salida como en el
valor devuelto por la función.

Éste último se usará generalmente como valor de control de posibles errores en la ejecución
cuando ello pueda suceder y será de tipo int. En ese caso un valor de retorno igual a 0 se
interpretará como una terminación normal.

Solamente si con seguridad la función terminará su ejecución normalmente se podrá utilizar


el valor de retorno con otra semántica que, en todo caso deberá describirse.

Estos comentarios relativos a la operación de las funciones y a la semántica de sus


parámetros deberán comenzar por una línea blanca seguida de otra de asteriscos (*) y
terminar de la misma forma.

En el archivo de implementación de una función e inmediatamente antes de la


implementación de ésta aparecerá un comentario del mismo estilo que el anterior pero
describiendo solamente cosas como el algoritmo de implementación, versión, etc. Todo
módulo iniciará con un comentario general que incluya:

Nombre del programa


Nombre del módulo:
Nombre del autor
Descripción general del módulo
Listado de las modificaciones realizadas

Según el ejemplo:

Funciones.c
/**********************************
* Programa: nomina.exe
* Módulo: funciones.c
* Autor: Jorge López Pérez
*
* Descripción:
* Módulo que contiene las funciones generales de acceso a datos
*
* Modificaciones:
* 12/Ene/2014 La función agregarUsuario se modificó para incluir un nuevo parámetro
* 20/Feb/2014 Se corrigió un error de validación en la función buscarUsuario
***********************************/

1
Todas las funciones incluirán un comentario que incluya:

Nombre de la función
Descripción de la función
Resultado de la función
Descripción de cada variable proporcionada como parámetro

Según el ejemplo:

/******************************************
* Función: iconvertirPeso
*
* Descripción:
* Dado una cantidad en pesos devuelve sus equivalencias en dólares, euros y libras, según el valor de unas
* constantes. Los parámetros de salida son pasados como referencia (apuntadores).
*
* Devuelve:
* un cero si todo estuvo bien y un 1 si la cantidad en pesos es menor o igual a cero
*
* Parámetros de entrada
* fpeso flotante pasado por valor que representa la cantidad en pesos
*
* Parámetros de salida
* pfdolar flotante pasado por referencia que contiene el equivalente en dolares
* pfeuro flotante pasado por referencia que contiene el equivalente en euros
* pflibra flotante pasado por referencia que contiene el equivalente en libras
*******************************************/
int iconvertirPeso (float fpeso, float *pfdolar, float *pfeuro, float *pflibra)

Los bloques complejos de código deberán incluir una descripción sencilla de lo que se
realiza cuando lo amerite. Evitar explicar cómo lo realiza.

while (( i < longitud) && (!encontrado) ) {

// Obtenemos la lista de la posicion i


lista_aux = g_list_nth (lista_listas, i);

// Selecionamos el primer elemento de cada lista de dentro de la lista.


particion = (TipoEspacioUsuario *) ((GList *) lista_aux->data)->data;

if (! strcmp (particion->particion->str, usuario->particion->str)) {


encontrado = TRUE;
}else
i++;
}
}

2
Los comentarios a una sentencia compuesta irán precedidos de una línea en blanco, y
ocuparán una o varias líneas inmediatamente antes de la sentencia comentada, a su mismo
nivel de sangrado, y poniendo un asterisco (*) al comenzar cada línea de comentario
distinta de la primera, y en la última escribimos el fin de comentario únicamente. Ejemplos:

/* Aqui vamos a comentar las acciones


* realizadas por el codigo fuente
*en varias líneas hasta terminar
*/
for(i = 1, j =100; i <= 10; i++, j -= 2, l <= 7 ?
FuncionA(): FuncionB()) {
...
}

Es necesario recordar que no deben usarse caracteres acentuados, eñes, etc. en los
comentarios. Los comentarios serán obligatorios para describir la semántica de una variable
cuando se defina.

Variables
Solo está permitido el uso de variables locales. Se deberá minimizar el uso de paso de
parámetros por referencia.

Los nombres de variables deberán reflejar el tipo de dato, así como el valor que almacena,
su ámbito, y si es un parámetro por referencia o valor.

Se utilizará la notación húngara para nombrar las variables.

Los nombres de variable se formarán mediante concatenaciones de palabras entre las que se
evitarán las abreviaturas y que comenzarán cada una por letra mayúscula. Dicha
concatenación irá precedida por una, dos o tres letras minúsculas que tendrán la misión de
indicar el tipo de la variable para información del programador. Ejemplos:

nUnaVariableEntera una variable entera corta (n)


pnUnaVariableEntera un apuntador a una variable entera corta (pn)

Los dígitos figurarán sólo excepcionalmente al final de los nombres de las variables.

Los nombres de variables de la forma i, j, k, l, m, n, o los formados por repeticiones de los


caracteres anteriores ii, jj, mmm, etc. se reservarán para su uso como índices de control de
bucles que no estén asociados a ningún significado especial.

Los nombres de variables de la forma p, q, r, s, o los formados por repeticiones de los


caracteres anteriores pp, qq, rr, etc. se reservarán para su uso como apuntadores auxiliares
que no estén asociados a ningún significado especial.

Se recomienda que en las declaraciones de variables se utilicen los modificadores de acceso


(const, volatile), longitud (short, long, signed, unsigned) y clase de almacenamiento (static,

3
register, extern) con la mayor precisión posible, de manera que el código pueda ser
controlado estrictamente por el sistema de desarrollo en las diversas fases de traducción-
enlace-depuración.

Es conveniente también tener en cuenta que los posibles inicializadores se describan en


términos de constantes simbólicas.

Los prefijos asociados a variables de los tipos más frecuentes serán los que se citan en la
tabla siguiente:
Tipo Prefijo
int n
unsigned int ui
short int si
unsigned short us
long int l
unsigned long ul
char c
unsigned char uc
signed char sc
float f
double d
long double ld
void * p
char * (terminado en ‘\0’) sz

Todas las variables que se declaren como apuntadores a uno de estos tipos antepondrán al
prefijo correspondiente una p salvo en el caso de void *.

Así un prefijo pc corresponderá a una variable declarada char *.

Los prefijos asociados a nombres de tipos definidos por el programador empezarán por t y
deben elegirse de forma análoga utilizando una o dos letras minúsculas más que indiquen el
nombre del tipo correspondiente y que no coincidan con los anteriores.

La elección que se haga figurará documentada mediante un comentario en el lugar en que


aparezca la sentencia typedef que defina el tipo.

Puede ser útil relajar la especificación de estilo anterior por comodidad de codificación,
pero se recomienda que sólo se haga para variables locales a una función, de modo que la
declaración de la variable esté próxima a sus posibles utilizaciones.

Ello es incluso típico en variables cuyo nombre es una sola letra (por ejemplo x, y, para
indicar coordenadas cartesianas) y en los elementos simples de las estructuras, cuyos
nombres no se usan nunca sin ser calificados.

4
En cualquier caso se desaconseja la relajación anterior en los nombres de variables de
ámbito global o de archivo y en los parámetros formales de las funciones.

Constantes
Con objeto de disponer de un código fácilmente configurable, éste deberá estar
completamente parametrizado, por lo cual todas las constantes de configuración utilizadas
deberán serlo a través de un nombre simbólico definido en un archivo de cabecera de
nombre CONSTCNF.H. En dicho archivo deberán figurar las definiciones de otras
constantes de uso en varios módulos aunque no sean de configuración, si bien se separarán
unas definiciones de otras agrupándolas en zonas distintas del archivo que se comentarán
por separado.

El resto de las constantes deberán tener asimismo un nombre simbólico que figurará
definido en el archivo de cabecera propio del módulo donde se usen. Los nombres de las
constantes se escribirán utilizando exclusivamente letras mayúsculas que se agruparán en
palabras que pueden interconectarse mediante el símbolo de subrayado (_). Ejemplos:

UNA_CONSTANTE;
OTRA_CONSTANTE_INTERESANTE;

Se desaconseja el uso de constantes simbólicas cuyo nombre comience o termine por el


símbolo de subrayado _, dado que es frecuente que esos nombres puedan tener algún uso
prefijado por el correspondiente sistema de desarrollo.

Es conveniente valorar la posibilidad de no usar directamente los nombres de las constantes


simbólicas en las expresiones si pueden ser sustituidas por nombres de variables declaradas
con el inicializador de control de acceso const e inicializadas con el valor de la constante a
través de su nombre.

Lo anterior permite un control de tipo en el uso de la variable y a la vez garantiza que ese
valor no puede ser alterado por una sentencia del programa. La desventaja que puede
presentar el citado método es que se consume tiempo de ejecución en el acceso a la
variable, que no es sustituida por su valor en tiempo de preproceso como lo sería el nombre
de la constante simbólica.

Funciones
Los nombres de funciones se formarán con las mismas reglas que los nombres de variables
salvo que no irán precedidos de ningún prefijo indicador de tipo. Así los nombres de
funciones comenzarán por mayúscula, pero ésta no deberá ser una T, letra que se reserva
como inicial de los nombres de tipo asignados por el programador (apartado “Tipos
definidos por el usuario”).

Se recomienda que los nombres de funciones se elijan para indicar lo que la función hace,
salvo en el caso de que su único efecto sea devolver un determinado valor, en cuyo caso el
nombre podría ser un nombre genérico para ese valor.

5
Es necesario que en las cabeceras de las funciones se use la forma estándar ANSI con
especificación de los tipos de cada parámetro formal y del tipo del valor de retorno
explícitamente.

Asimismo en los prototipos se harán constar los nombres de los parámetros formales
usados en la definición, porque, aunque en este lugar no son necesarios, ayudan a la
comprensión de la utilización de la función en cuestión; por otra parte ello permite formar
el prototipo copiando simplemente la cabecera de la definición de la función y añadiéndole
un punto y coma (;). Ejemplos:

int RealizarUnCalculo(short siPrimerParametro,


float fSegundoParametro);
int ValorDevuelto(double dParametro);

Tipos definidos por el usuario


Los nombres de tipo definidos por el programador se asignarán con las mismas reglas que
los nombres de función, pero las dos primeras letras serán mayúsculas y la primera una T.

Todas las definiciones typedef que afecten a más de un módulo se reunirán en el archivo
GLOBALTP.H, mientras que las que afecten sólo a un módulo estarán colocadas en el
archivo de cabecera de dicho módulo. Ejemplos:

TTipoEjemplo;
TOtroTipoDiferente;

Formato de código
Cada bloque de código estará separado por una línea en blanco. Se utilizarán tabuladores y
espacios para indentar el código dentro de las estructuras.

// Creamos el usuario con los datos obtenidos


usuario = g_new(TipoEspacioUsuario, 1);

usuario->nombre = g_string_new ("Ficheros de sistema");


usuario->particion = g_string_new (cadena_aux);
usuario->espacio = espacio_acumulado;

lista_part = g_list_append (lista_part, usuario);

Las llaves deben utilizarse según el siguiente esquema, poner la llave de apertura al final
de la línea y poner la llave de cierre al principio, como en este ejemplo:

if (x es verdad) {
haremos y
}

6
Sin embargo, hay un caso especial, la definición de funciones: estas tienen la llave de
apertura al principio de la línea siguiente:

int función(int x)
{
cuerpo de la función
}

Observe bien que la llave de cierre es el único carácter en su línea, excepto en los casos
donde está seguida por una continuación de la misma función, como un "while" en una
función do, o un "else" en una función if. Por ejemplo:

do {
cuerpo del bucle do
} while (condición);

if (x == y) {
..
} else if (x > y) {
...
} else {
....
}

Solamente comenzarán en columna 1 los elementos sintácticos que se citan a continuación


y ello siempre que no estén incluidos en otro bloque:
 Directivas del preprocesador que vayan a afectar al ámbito de los bloques del nivel
más externo que les sigan.
 Sentencias typedef que aparezcan en el ámbito global (externo a las definiciones de
funciones).
 Definiciones de variables globales.
 Declaraciones de variables globales.
 Cabeceras de definición de funciones.
 Prototipos de funciones.
 Llaves de apertura y cierre de los bloques de definición de las funciones.
 Comentarios a cualquiera de los ítems anteriores y que vayan en línea o líneas
previas.

Todas las demás frases comenzarán, al menos, en el primer nivel de sangrado.

Se recomienda que las frases de código no pasen de la columna 72. Si es necesario


continuar en la línea siguiente, se hará siempre que sea posible sin carácter de continuación
de línea y en el siguiente nivel de sangrado.

Nombres de los archivos


Se propone como regla de formación de los nombres de los archivos la utilización de los
nombres de los módulos del sistema como parte inicial del nombre, reservando algún
carácter para indicar la versión.

7
La extensión del nombre de un archivo fuente deberá indicar si es un archivo de interfaz
público de utilización del módulo (.H), si es un archivo de interfaz completo (.HPP) o si es
un archivo de implementación (.C).

Organización del código

Variables globales
Para el manejo de las variables globales se usarán dos archivos. El primero de ellos
GLOBALV.C contendrá las declaraciones de las variables que no correspondan a ningún
módulo en particular, y, en su caso, tales declaraciones incluirán los inicializadores
correspondientes.

En un segundo archivo GLOBALV.H se repetirán las declaraciones de las variables


anteriores sin inicializadores y precedidas del especificador extern con objeto de que dichas
declaraciones puedan ser utilizadas en cualquier módulo que las necesite mediante la
inclusión correspondiente.

Ocultamiento de variables y funciones privadas a un módulo


La forma de conseguir el ocultamiento hacia el exterior de un módulo de sus variables y/o
funciones privadas consiste en declararlas con el especificador de clase de almacenamiento
static.

Ello es innecesario con las variables locales a un bloque (por ejemplo las variables locales
de una función), porque el ámbito del identificador se reduce siempre al bloque en el que
está definido, o incluso a una parte de él solamente. Además el especificador static para las
variables locales a un bloque afecta a la duración de la variable y no a su ámbito.

Se aconseja pues que un módulo esté formado por tres archivos:


 Un archivo de cabecera (con extensión H) que contenga la interfaz pública del
módulo. Estarían allí las declaraciones de variables compartidas por los objetos
software cuya funcionalidad está descrita por el módulo y que dichos objetos
puedan manipular (esto es, que deban exportarse desde el módulo) precedidas del
especificador extern.
Además estarían allí los prototipos de las funciones exportadas para esa clase de
objetos y las definiciones de tipo que deban ser exportadas para poder manipular los
objetos cuya funcionalidad se describe en el módulo. Este archivo debería ser
incluido para poder utilizar la funcionalidad del módulo en los archivos fuente que
la usen.
 Otro archivo de cabecera (con extensión HPP) que contendrá todos los prototipos de
las funciones privadas del módulo declarados con el especificador static y todos los
prototipos de las funciones que se encuentran declarados en el archivo de cabecera
anterior, así como las definiciones de tipo exportadas.
Asimismo figurarán en este archivo todas las definiciones de constantes simbólicas
y tipos que sean de uso privado en el módulo.

8
Este archivo no deberá utilizarse más que para poder compilar el tercero de los
componentes del módulo (archivo de implementación).
 Un archivo de implementación (con extensión C) en el que deberá incluirse el
segundo de los archivos de cabecera (que se usará sólo para la compilación de éste)
y en el que figurarán las definiciones de todas las variables globales del módulo
ordenadas en dos grupos: En el primero estarán las definiciones correspondientes al
interfaz público mientras que en el segundo estarán las privadas definidas todas
ellas con el especificador static.
Posteriormente se describirán las implementaciones de todas las funciones de cada
subgrupo (públicas y privadas) ordenadas de la misma forma.

Organización de los archivos de un proyecto


Es conveniente organizar los archivos de un proyecto asignando a éste un directorio
diferente del de los demás proyectos, incluso si se trata de una nueva versión de un
proyecto ya desarrollado.

Dentro del directorio del proyecto crearemos subdirectorios para contener los diferentes
tipos de archivos.

Un directorio de nombre INCLUDE contendrá todos los archivos de cabecera (extensiones


H y HPP).

Un directorio de nombre SOURCE contendrá los archivos de implementación de los


módulos (extensión C).

Un directorio de nombre OBJECT contendrá la salida del compilador (archivos objeto)

Un directorio LIB contendrá las bibliotecas propias del proyecto (esto es, no estándares)
que deban usarse.

El propio directorio del proyecto contendrá los archivos ejecutables que deban generarse.
Se encontrarán además aquellos archivos con información general, por ejemplo los archivos
make.

A veces los entornos de desarrollo requieren que los archivos objeto residan donde el
ejecutable. En ese caso ambos tipos de ficheros residirán en el directorio del proyecto.

Un directorio de nombre DOC contendrá archivos de descripción y documentación


generales (informaciones sobre versiones, estados del entorno de desarrollo si se guardan,
etc.)

También podría gustarte