Guía de estilo de programación en C++ estructurado
Guía de estilo de programación en C++ estructurado
Guía de estilo de programación en C++ estructurado
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Guía</strong> <strong>de</strong> <strong>estilo</strong> <strong>de</strong> <strong>programación</strong> <strong>en</strong> <strong>C++</strong><br />
<strong>estructurado</strong><br />
Pequeños consejos sobre cómo escribir programas más legibles.
Índice<br />
1Introducción........................................................................................................................................3<br />
2Indicaciones g<strong>en</strong>erales........................................................................................................................3<br />
3I<strong>de</strong>ntificadores....................................................................................................................................4<br />
3.1I<strong>de</strong>ntificadores <strong>de</strong> estructuras.....................................................................................................4<br />
3.2I<strong>de</strong>ntificadores <strong>de</strong> campos..........................................................................................................5<br />
3.3I<strong>de</strong>ntificadores <strong>de</strong> registros.........................................................................................................5<br />
3.4I<strong>de</strong>ntificadores <strong>de</strong> funciones.......................................................................................................5<br />
3.5I<strong>de</strong>ntificadores <strong>de</strong> variables locales <strong>en</strong> funciones.......................................................................5<br />
3.6Ejemplo con estructuras, variables y funciones..........................................................................6<br />
3.7Declaración <strong>de</strong> variables.............................................................................................................7<br />
4Com<strong>en</strong>tarios........................................................................................................................................8<br />
4.1Com<strong>en</strong>tarios <strong>de</strong> inicio <strong>de</strong> bloque................................................................................................8<br />
4.2Com<strong>en</strong>tarios aclaratorios............................................................................................................8<br />
4.3Com<strong>en</strong>tarios sobre funciones y procedimi<strong>en</strong>tos.........................................................................8<br />
5Disposición <strong>de</strong> elem<strong>en</strong>tos.................................................................................................................10<br />
5.1Estructuras................................................................................................................................10<br />
5.1.1Unida<strong>de</strong>s <strong>de</strong> traducción.....................................................................................................10<br />
5.2Funciones..................................................................................................................................11<br />
5.2.1Estructuras <strong>de</strong> <strong>de</strong>cisión y repetición..................................................................................12<br />
5.2.1.1Cuerpos <strong>de</strong> instrucciones <strong>de</strong> una sola línea...............................................................12<br />
5.3Espaciado..................................................................................................................................13
1 Introducción<br />
En este docum<strong>en</strong>to se explica brevem<strong>en</strong>te, y con ejemplos, cómo escribir programas más legibles.<br />
A lo largo <strong>de</strong> su vida profesional, cualquier programador se plantea la pregunta <strong>de</strong> cómo escribir sus<br />
programas <strong>de</strong> manera que sean más legibles, y por tanto que puedan ser mant<strong>en</strong>idos (corrección <strong>de</strong><br />
errores, ampliación <strong>de</strong> funcionalidad) con facilidad, tanto por él mismo como por otros<br />
programadores (una situación típica <strong>en</strong> cualquier empresa).<br />
Dado que la misma situación <strong>en</strong> cuanto a legibilidad <strong>de</strong> código suele ser resuelta por<br />
distintos programadores <strong>de</strong> la misma forma, pero con distintos matices <strong>de</strong> difer<strong>en</strong>ciación, es<br />
interesante seguir una guía <strong>de</strong> <strong>estilo</strong> que nos explique como otros resolvieron ese mismo problema,<br />
hasta que dicha solución se convirtió <strong>en</strong> un estándar.<br />
2 Indicaciones g<strong>en</strong>erales<br />
El propósito <strong>de</strong> seguir una norma <strong>de</strong> <strong>estilo</strong> es hacer que el código fu<strong>en</strong>te <strong>de</strong> un programa sea tan<br />
legible como sea posible. Así, hay tres puntos básicos que se <strong>de</strong>b<strong>en</strong> cuidar: el espaciado horizontal,<br />
el espaciado vertical y la in<strong>de</strong>ntación. El espaciado horizontal consiste <strong>en</strong> que las líneas <strong>en</strong> las que<br />
esté dividido el código fu<strong>en</strong>te <strong>de</strong>b<strong>en</strong> ser <strong>de</strong> una longitud máxima lo más próxima posible a 80<br />
caracteres, ya que al imprimir el código <strong>en</strong> papel cualquier línea superior a 80 columnas se <strong>de</strong>scarta<br />
automáticam<strong>en</strong>te.<br />
Uno <strong>de</strong> los problemas que se pue<strong>de</strong> <strong>en</strong>contrar al codificar es la manera más correcta para<br />
dividir una línea muy larga. Respuestas comunes a esta pregunta son: antes <strong>de</strong> una subexpresión,<br />
antes <strong>de</strong> un operador, o antes <strong>de</strong> un paréntesis. Por ejemplo:<br />
int x = ( (a * b + c ) / ( c * d * d ) )<br />
+ ( a / ( b * c ) )<br />
+ ( ( 3.1451927 * b ) + d )<br />
;<br />
Los operadores <strong>de</strong>b<strong>en</strong> separarse mediante espacios para mayor claridad, a excepción hecha<br />
<strong>de</strong> operadores unarios como el increm<strong>en</strong>to o <strong>de</strong>crem<strong>en</strong>to, tanto postfijo como prefijo, que suel<strong>en</strong><br />
colocarse pegados al operando al que modifican (lo más típico, por claridad), pero también pue<strong>de</strong>n<br />
colocarse espaciados, a elección <strong>de</strong>l programador.<br />
int x = ++ i;<br />
int y = j++ + ++ x;<br />
El espaciado vertical consiste <strong>en</strong> cuántas líneas ocupa una función o una estructura, <strong>en</strong> el<br />
código fu<strong>en</strong>te. En g<strong>en</strong>eral, es útil autoimponerse un límite <strong>de</strong> una hoja por cada función o<br />
procedimi<strong>en</strong>to. Es extraño, siempre que la misma no consista <strong>en</strong> multitud <strong>de</strong> acciones repetitivas<br />
(como escribir <strong>en</strong> un archivo), que una función bi<strong>en</strong> diseñada ocupe más allá <strong>de</strong> un folio. En caso<br />
contrario, será conv<strong>en</strong>i<strong>en</strong>te consi<strong>de</strong>rar que posiblem<strong>en</strong>te sea interesante subdividirlo <strong>en</strong> varias<br />
subfunciones (probablem<strong>en</strong>te <strong>de</strong> acceso privado).<br />
A<strong>de</strong>más, <strong>en</strong> el espaciado vertical intervi<strong>en</strong><strong>en</strong> las llaves que se emplean para marcar el<br />
comi<strong>en</strong>zo y fin <strong>de</strong>l cuerpo <strong>de</strong> una función, <strong>de</strong> un bucle, ... cada una <strong>de</strong> esas llaves pue<strong>de</strong> llegar a<br />
consumir una línea por sí sola, incluso dos. Así, para salvar algo <strong>de</strong> espacio vertical, se suel<strong>en</strong><br />
mant<strong>en</strong>er las llaves <strong>de</strong> apertura y cierre, cada una <strong>en</strong> una línea, para el cuerpo <strong>de</strong> las funciones, y <strong>en</strong><br />
cambio colocar la llave <strong>de</strong> apertura <strong>en</strong> la misma línea para bucles y estructuras <strong>de</strong> <strong>de</strong>cisión. Por<br />
ejemplo:
int dividir(int a, int b)<br />
{<br />
if ( b != 0 ) {<br />
return a / b;<br />
}<br />
}<br />
return 0;<br />
... (recuér<strong>de</strong>se que <strong>en</strong> un programa real será mucho más a<strong>de</strong>cuado respon<strong>de</strong>r a la<br />
conting<strong>en</strong>cia que supone dividir un número <strong>en</strong>tre cero, que respon<strong>de</strong>r con cero “sil<strong>en</strong>ciosam<strong>en</strong>te”,<br />
lo cual supone un error no <strong>de</strong>tectado).<br />
La in<strong>de</strong>ntación es vital para po<strong>de</strong>r compr<strong>en</strong><strong>de</strong>r rápidam<strong>en</strong>te los elem<strong>en</strong>tos funcionales <strong>de</strong> un<br />
programa. Así, el cuerpo (las instrucciones) <strong>de</strong> una función o procedimi<strong>en</strong>to <strong>de</strong>be estar alineado <strong>en</strong><br />
su marg<strong>en</strong> izquierdo más a la <strong>de</strong>recha que su cabecera, <strong>de</strong> la misma forma que un bucle <strong>de</strong>ntro <strong>de</strong><br />
esa función y así sucesivam<strong>en</strong>te. Por ejemplo:<br />
int elevarA(int x, int y)<br />
{<br />
int toret = 1;<br />
}<br />
if ( y >= 0 ) {<br />
for(; y > 0; --y) {<br />
toret *= x;<br />
}<br />
} else toret = 0<br />
return toret;<br />
3 I<strong>de</strong>ntificadores<br />
Los i<strong>de</strong>ntificadores se utilizan <strong>en</strong> varias (innumerables) ocasiones <strong>en</strong> <strong>programación</strong>: <strong>en</strong>umeraciones,<br />
funciones, constantes, variables locales ..., y son claves para <strong>en</strong>t<strong>en</strong><strong>de</strong>r qué valores pue<strong>de</strong> cont<strong>en</strong>er<br />
una variable, qué hace una función o a qué valores repres<strong>en</strong>ta un <strong>en</strong>umerado. Por eso, hay que poner<br />
especial cuidado <strong>en</strong> su elección. También será interesante seguir unas pequeñas reglas a la hora <strong>de</strong><br />
escribir un i<strong>de</strong>ntificador que hagan que a su vez podamos obt<strong>en</strong>er el máximo significado <strong>de</strong>l mismo<br />
si se está ley<strong>en</strong>do <strong>en</strong> un listado.<br />
En g<strong>en</strong>eral, los i<strong>de</strong>ntificadores <strong>de</strong>b<strong>en</strong> ser tan cortos como sea posible, pero a la vez tan<br />
informativos como sea posible. Muchas veces, a<strong>de</strong>más, es imposible utilizar un solo sustantivo para<br />
nombrar una variable, función o estructura; <strong>en</strong> ese caso, se concat<strong>en</strong>arán todos para formar el<br />
i<strong>de</strong>ntificador final, poni<strong>en</strong>do cada inicial <strong>en</strong> mayúscula. Si bi<strong>en</strong> algunos l<strong>en</strong>guajes mo<strong>de</strong>rnos lo<br />
permit<strong>en</strong> (como Java), a través <strong>de</strong>l soporte unico<strong>de</strong>, evít<strong>en</strong>se los ac<strong>en</strong>tos, las diéresis ... <strong>en</strong> los<br />
i<strong>de</strong>ntificadores.<br />
3.1 I<strong>de</strong>ntificadores <strong>de</strong> estructuras<br />
Los i<strong>de</strong>ntificadores <strong>de</strong> estructuras <strong>de</strong>berían correspon<strong>de</strong>rse con sustantivos <strong>de</strong> la vida real o <strong>de</strong>l<br />
concepto que se está mo<strong>de</strong>lando con el programa. Así, i<strong>de</strong>ntificadores <strong>de</strong> estructuras típicos pue<strong>de</strong>n<br />
ser: Casa, Coche, Barco, Cu<strong>en</strong>ta ...<br />
El i<strong>de</strong>ntificador <strong>de</strong> la estructura, <strong>en</strong> caso <strong>de</strong> estar compuesto por más <strong>de</strong> una palabra, se<br />
construye concat<strong>en</strong>ando todas las palabras, y poni<strong>en</strong>do la inicial <strong>de</strong> cada una <strong>de</strong> estas palabras <strong>en</strong><br />
mayúsculas. Por ejemplo: Cu<strong>en</strong>taCorri<strong>en</strong>te, Cu<strong>en</strong>taCredito ...
struct Rectangulo {<br />
// más cosas ...<br />
};<br />
struct Cu<strong>en</strong>taCorri<strong>en</strong>te {<br />
// más cosas ...<br />
};<br />
3.2 I<strong>de</strong>ntificadores <strong>de</strong> campos<br />
Los i<strong>de</strong>ntificadores <strong>de</strong> campos (o datos miembro), sigu<strong>en</strong> las mismas normas que los <strong>de</strong> las<br />
estructuras, pero con la primera inicial <strong>en</strong> minúscula. Así, por ejemplo, i<strong>de</strong>ntificadores válidos son<br />
i<strong>de</strong>ntificadorCompleto, precioEuros, ...<br />
struct Cu<strong>en</strong>taCorri<strong>en</strong>te {<br />
double saldoEuros;<br />
};<br />
3.3 I<strong>de</strong>ntificadores <strong>de</strong> registros<br />
Los i<strong>de</strong>ntificadores <strong>de</strong> registros (o variables <strong>de</strong> las estructuras) sigu<strong>en</strong> las mismas reglas que los<br />
i<strong>de</strong>ntificadores <strong>de</strong> los campos.<br />
3.4 I<strong>de</strong>ntificadores <strong>de</strong> funciones<br />
Los i<strong>de</strong>ntificadores <strong>de</strong> funciones sigu<strong>en</strong> las mismas reglas que para campos y registros. Sin<br />
embargo, <strong>de</strong>b<strong>en</strong> escogerse <strong>de</strong> modo que sugieran <strong>de</strong> manera intuitiva qué hac<strong>en</strong>. Así, el<br />
i<strong>de</strong>ntificador <strong>de</strong>be ser un verbo o al m<strong>en</strong>os cont<strong>en</strong>er uno. Las funciones que <strong>de</strong>vuelv<strong>en</strong> un valor<br />
lógico <strong>de</strong>berían t<strong>en</strong>er un verbo copulativo (ser o estar) al comi<strong>en</strong>zo <strong>de</strong>l i<strong>de</strong>ntificador.<br />
double calculaArea(Triangulo);<br />
int esPalindromo(const char *);<br />
Evít<strong>en</strong>s<strong>en</strong> i<strong>de</strong>ntificadores como los sigui<strong>en</strong>tes:<br />
int procesar(Cu<strong>en</strong>taCorri<strong>en</strong>te c); // Mal: i<strong>de</strong>ntificador no intuitivo<br />
void pasoAuxiliar(Rectagulo r); // Mal: i<strong>de</strong>ntificador simplem<strong>en</strong>te erróneo<br />
void procesaYCu<strong>en</strong>ta(); // Mal: Dividir <strong>en</strong> dos funciones<br />
Cuando un i<strong>de</strong>ntificador conti<strong>en</strong>e una conjunción como y, es signo inequívoco <strong>de</strong> que la<br />
función que nombra realiza más <strong>de</strong> una tarea y <strong>de</strong>be ser por tanto separada <strong>en</strong> dos funciones<br />
separadas.<br />
Los mejores i<strong>de</strong>ntificadores son aquellos que <strong>de</strong>scrib<strong>en</strong> con un i<strong>de</strong>ntificador más corto lo<br />
que hace la función. A<strong>de</strong>más, es interesante seguir ciertas pautas: <strong>en</strong> el caso <strong>de</strong> funciones que<br />
<strong>de</strong>vuelv<strong>en</strong> un booleano (un valor verda<strong>de</strong>ro o falso), es interesante nombrarlos con un prefijo<br />
formado por los verbos ser o estar, como:<br />
esPalindromo(const char s[]);<br />
esPar(int);<br />
fueModificada(const Cu<strong>en</strong>taCorri<strong>en</strong>te c);<br />
3.5 I<strong>de</strong>ntificadores <strong>de</strong> variables locales <strong>en</strong> funciones<br />
En el caso <strong>de</strong> variables locales <strong>de</strong> funciones, exist<strong>en</strong> varias particularida<strong>de</strong>s. Por ejemplo, a las<br />
variables locales empleadas <strong>en</strong> bucles se les suele asignar i<strong>de</strong>ntificadores <strong>de</strong> una letra tipo 'i' y 'j',<br />
también <strong>en</strong> el caso <strong>de</strong> algunos argum<strong>en</strong>tos simples (si bi<strong>en</strong> este caso es mejor, sin embargo, evitarlo,
cuando sea posible, y asignar i<strong>de</strong>ntificadores <strong>de</strong>scriptivos) <strong>de</strong> funciones.<br />
void cnvtMayusculas(char s[])<br />
{<br />
int i = 0;<br />
}<br />
for(; s[ i ] != 0; ++i) {<br />
s[ i ] = toupper( s[ i ] );<br />
}<br />
Los i<strong>de</strong>ntificadores <strong>de</strong> variables también pue<strong>de</strong>n informar sobre para qué se utiliza esa<br />
variable, y no restringirse a tan solo información sobre qué valores alberga. Por ejemplo, <strong>en</strong> el<br />
código sigui<strong>en</strong>te toret (a retornar) es una variable que se utiliza <strong>en</strong> todas las funciones para <strong>de</strong>volver<br />
un valor.<br />
int calcularLongitud(const char s[])<br />
{<br />
int toret = 0;<br />
}<br />
for(; s[ toret ] != 0; ++toret) {<br />
}<br />
return toret;<br />
3.6 Ejemplo con estructuras, variables y funciones<br />
A continuación, se muestra un ejemplo completo:<br />
#inclu<strong>de</strong> <br />
const double PI = 3.1415927;<br />
struct Circulo {<br />
double radio;<br />
double perimetro;<br />
double area;<br />
};<br />
void calcularDatos(const Circulo &c)<br />
/* Completar la estructura círculo con los datos a<strong>de</strong>cuados */<br />
{<br />
c.area = c.radio * c.radio * PI;<br />
c.perimetro = 2 * PI * c.radio;<br />
}<br />
int main(void)<br />
{<br />
Circulo miCirculo;<br />
}<br />
printf( “Introduzca el radio <strong>de</strong>l círculo: “ );<br />
scanf( “%f”, &miCirculo.radio );<br />
calcularDatos( miCirculo );<br />
printf( “Círculo <strong>de</strong> radio: %f\n\tÁrea: %f\n\tPerímetro: %f\n”,<br />
miCirculo.radio,<br />
miCirculo.area,<br />
miCirculo.perimetro<br />
);
3.7 Declaración <strong>de</strong> variables<br />
Se <strong>de</strong>be colocar cada variable <strong>en</strong> una línea, incluso si<strong>en</strong>do <strong>de</strong>l mismo tipo.<br />
int x, y; // Es necesaria una segunda mirada para fijarse <strong>en</strong> 'y'<br />
int main()<br />
{<br />
int x;<br />
int y;<br />
char c;<br />
char toret[128];<br />
}<br />
// más cosas ...<br />
return 0;<br />
C permite minimizar muchísimo ciertas expresiones. Por ejemplo, el sigui<strong>en</strong>te bucle copiaría<br />
una ca<strong>de</strong>na <strong>de</strong> caracteres <strong>de</strong> C (un vector <strong>de</strong> char), <strong>en</strong> otra <strong>de</strong> <strong>de</strong>stino:<br />
void copiaCa<strong>de</strong>na(char cadDestino[], const char cadOrig<strong>en</strong>[])<br />
{<br />
int i = 0;<br />
while( cadDestino[ i ] = cadOrig<strong>en</strong>[ i++ ] );<br />
}<br />
Esto es bu<strong>en</strong>o <strong>en</strong> cuanto a espaciado vertical, <strong>de</strong>s<strong>de</strong> luego, pero <strong>de</strong>be valorarse cuándo el<br />
ahorro <strong>de</strong> espaciado merma la legibilidad <strong>de</strong>l código.<br />
void copiaCa<strong>de</strong>na(char cadDestino[], const char cadOrig<strong>en</strong>[])<br />
{<br />
int i = 0;<br />
for(; cadOrig<strong>en</strong>[ i ] != 0; ++i) {<br />
cadDestino[ i ] = cadOrig<strong>en</strong>[ i ];<br />
}<br />
}<br />
La anterior función realiza la misma tarea que la pre<strong>de</strong>cesora. Sin embargo, está<br />
perfectam<strong>en</strong>te claro cuándo el bucle termina (al llegar a la marca <strong>de</strong> fin <strong>de</strong> ca<strong>de</strong>na <strong>de</strong> la ca<strong>de</strong>na <strong>de</strong><br />
orig<strong>en</strong>), cuándo se hace explícitam<strong>en</strong>te una copia y también cuándo, <strong>de</strong>spués, se increm<strong>en</strong>tan ambos<br />
contadores. Es una función que se pue<strong>de</strong> compr<strong>en</strong><strong>de</strong>r <strong>de</strong> un vistazo, mi<strong>en</strong>tras que la anterior, aún<br />
para un programador con experi<strong>en</strong>cia, supondrá invertir unos cuantos segundos. Finalm<strong>en</strong>te, la<br />
calidad <strong>de</strong>l código máquina g<strong>en</strong>erada es la misma <strong>en</strong> ambos casos, si bi<strong>en</strong> es cierto que el primer<br />
ejemplo podría g<strong>en</strong>erar, según el compilador, un número <strong>de</strong> instrucciones máquina algo m<strong>en</strong>or.<br />
4 Com<strong>en</strong>tarios<br />
Un com<strong>en</strong>tario <strong>de</strong>be ser siempre clarificador, útil, y, <strong>en</strong> cambio, cuanto más corto mejor. En<br />
particular, <strong>de</strong>be cuidarse <strong>en</strong> no insultar la intelig<strong>en</strong>cia <strong>de</strong>l lector <strong>en</strong> <strong>de</strong>terminadas ocasiones,<br />
com<strong>en</strong>tando secu<strong>en</strong>cias <strong>de</strong> código obvias y <strong>de</strong>sesperarlo al <strong>en</strong>contrarse con construcciones<br />
complejas que no ti<strong>en</strong><strong>en</strong> ningún com<strong>en</strong>tario.
int areaRectangulo = lado1 * lado2; // calcula área<br />
areaCirculo = PI * r * r; // calcula área <strong>de</strong>l círculo<br />
// PI es 3.1415927<br />
En el contexto <strong>de</strong>l ejemplo anterior, el tercer com<strong>en</strong>tario es absolutam<strong>en</strong>te innecesario,<br />
mi<strong>en</strong>tras que los dos primeros son cuestionables, siempre que los i<strong>de</strong>ntificadores hayan sido<br />
escogidos cuidadosam<strong>en</strong>te, como es el caso.<br />
4.1 Com<strong>en</strong>tarios <strong>de</strong> inicio <strong>de</strong> bloque<br />
Exist<strong>en</strong> dos tipos básicos <strong>de</strong> com<strong>en</strong>tarios, los que podríamos <strong>de</strong>nominar com<strong>en</strong>tarios <strong>en</strong>cima, y los<br />
que podríamos <strong>de</strong>nominar com<strong>en</strong>tarios a la <strong>de</strong>recha. Los más recom<strong>en</strong>dables son los primeros,<br />
pues suel<strong>en</strong> explicar un bloque <strong>de</strong> código, a modo <strong>de</strong> párrafo, aclarando mucho la lectura.<br />
void listarPersonas(char buffer[], const Persona &vp[MaxPersonas])<br />
/**<br />
@param buffer vector <strong>de</strong> caracteres para listado<br />
@param vp vector <strong>de</strong> personas a listar<br />
*/<br />
{<br />
*buffer = 0;<br />
int i = 0;<br />
}<br />
// Obt<strong>en</strong>er los nombres <strong>de</strong> cada persona<br />
for(; i < MaxPersonas; ++i) {<br />
strcat( buffer, vp[ i ].nombre );<br />
strcat( buffer, “\n” );<br />
}<br />
return buffer;<br />
Como pue<strong>de</strong> observarse, el com<strong>en</strong>tario <strong>de</strong> la función sigue un formato específico, que se discutirá<br />
<strong>en</strong> las sigui<strong>en</strong>tes secciones.<br />
4.2 Com<strong>en</strong>tarios aclaratorios<br />
Los com<strong>en</strong>tarios a la <strong>de</strong>recha <strong>de</strong>b<strong>en</strong> emplearse como m<strong>en</strong>sajes aclaratorios, int<strong>en</strong>tando mant<strong>en</strong>er<br />
especialm<strong>en</strong>te <strong>en</strong> ellos la concisión, pues es fácil que se alcanc<strong>en</strong> rápidam<strong>en</strong>te más <strong>de</strong> och<strong>en</strong>ta<br />
caracteres <strong>en</strong> esa línea. Agravando aún más este último problema, <strong>de</strong>b<strong>en</strong> colocarse alejados <strong>de</strong>l<br />
código que aclaran para que sean visibles.<br />
// Cálculos previos al r<strong>en</strong><strong>de</strong>ring<br />
areaRectangulo = lado1 * lado2; // <strong>en</strong> cms<br />
4.3 Com<strong>en</strong>tarios sobre funciones y procedimi<strong>en</strong>tos<br />
Des<strong>de</strong> la llegada <strong>de</strong>l l<strong>en</strong>guaje Java, y su herrami<strong>en</strong>ta <strong>de</strong> docum<strong>en</strong>tación, Javadoc, se han<br />
g<strong>en</strong>eralizado los com<strong>en</strong>tarios formateados con un <strong>de</strong>terminado <strong>estilo</strong>, y aceptando unos<br />
<strong>de</strong>terminados parámetros <strong>de</strong> docum<strong>en</strong>tación embebidos <strong>en</strong> ellos. Para el l<strong>en</strong>guaje C, existe también<br />
un equival<strong>en</strong>te a Javadoc, la herrami<strong>en</strong>ta Doxyg<strong>en</strong> 1 , <strong>de</strong> gran aceptación.<br />
Así, cuando un com<strong>en</strong>tario, <strong>en</strong> lugar <strong>de</strong> empezar por /*, comi<strong>en</strong>za por /**, al pasar el código<br />
por la herrami<strong>en</strong>ta Doxyg<strong>en</strong>, ésta g<strong>en</strong>era la docum<strong>en</strong>tación recogida <strong>en</strong> varios formatos (incluy<strong>en</strong>do<br />
el HTML, que lo hace i<strong>de</strong>al para las refer<strong>en</strong>cias cruzadas). Estos com<strong>en</strong>tarios también son útiles al<br />
<strong>de</strong>snudo, por lo que <strong>de</strong>b<strong>en</strong> colocarse <strong>en</strong> las cabeceras (los ficheros con ext<strong>en</strong>sión .h, don<strong>de</strong> se<br />
1 Doxyg<strong>en</strong> pue<strong>de</strong> <strong>en</strong>contrarse <strong>en</strong>: http://www.doxyg<strong>en</strong>.org
<strong>de</strong>claran las clases; consúltese la sección sobre unida<strong>de</strong>s <strong>de</strong> traducción), inmediatam<strong>en</strong>te antes <strong>de</strong><br />
cada estructura, función, o campo. Son las cabeceras las que serán consultadas por el programador<br />
que utilice el módulo para conocer su interfaz pública.<br />
// rectangulo.h<br />
/**<br />
La estructura que repres<strong>en</strong>ta a los rectángulos<br />
*/<br />
struct Rectangulo {<br />
/// La información sobre la base <strong>de</strong>l rectángulo<br />
double base;<br />
/// La información sobre la altura <strong>de</strong>l rectángulo<br />
double altura;<br />
};<br />
/**<br />
* Creador <strong>de</strong> rectángulos<br />
* @param b La base <strong>de</strong>l futuro rectángulo<br />
* @param a La altura <strong>de</strong>l futuro rectángulo<br />
*/<br />
Rectangulo creaRectangulo(double b, double a);<br />
/**<br />
* Calcula el área <strong>de</strong>l rectángulo<br />
* @return El área <strong>de</strong>l rectángulo, según sus lados<br />
*/<br />
double calcularArea(const Rectangulo &r);<br />
// rectangulo.cpp<br />
/*<br />
Implem<strong>en</strong>tación <strong>de</strong>l TDA rectángulo.<br />
*/<br />
#inclu<strong>de</strong> “rectangulo.h”<br />
Rectangulo creaRectangulo(double b, double a)<br />
{<br />
Rectangulo toret;<br />
toret.base = b;<br />
toret.altura = a;<br />
return toret;<br />
}<br />
double calcularArea(const Rectangulo &r)<br />
{<br />
return ( r.base * r.altura );<br />
}<br />
De los parámetros que se pue<strong>de</strong>n utilizar <strong>en</strong> este tipo <strong>de</strong> com<strong>en</strong>tarios, <strong>de</strong>stacan @param y<br />
@return. El primero sirve para docum<strong>en</strong>tar un parámetro <strong>de</strong> una función o procedimi<strong>en</strong>to, tal y<br />
como se ve <strong>en</strong> la función crearRectángulo() <strong>de</strong>l módulo Rectángulo <strong>de</strong> ejemplo, más arriba. El<br />
segundo sirve para docum<strong>en</strong>tar el valor <strong>de</strong> retorno <strong>de</strong> una función, tal y como se aprecia <strong>en</strong> la<br />
función calcularArea() <strong>de</strong>l módulo <strong>de</strong>l mismo ejemplo. Por último, con @see es posible hacer<br />
refer<strong>en</strong>cias cruzadas <strong>en</strong>tre funciones y estructuras <strong>de</strong> datos, por ejemplo.
5 Disposición <strong>de</strong> elem<strong>en</strong>tos<br />
5.1 Estructuras<br />
Al igual que al tratar con variables locales, <strong>de</strong>b<strong>en</strong> colocarse los miembtos <strong>de</strong> una estructura uno <strong>en</strong><br />
cada línea. Debe aprovecharse para docum<strong>en</strong>tar a<strong>de</strong>cuadam<strong>en</strong>te la <strong>en</strong>tidad. Si el significado <strong>de</strong> los<br />
miembros no es obvio, <strong>en</strong>tonces, <strong>de</strong>b<strong>en</strong> añadirse com<strong>en</strong>tarios para cada campo.<br />
/// Estructura que repres<strong>en</strong>ta a puntos <strong>de</strong> dos dim<strong>en</strong>siones<br />
struct Punto {<br />
double x;<br />
double y;<br />
};<br />
5.1.1 Unida<strong>de</strong>s <strong>de</strong> traducción<br />
En terminología C, el compilador traduce a código máquina unida<strong>de</strong>s <strong>de</strong> traducción, que son<br />
ficheros con ext<strong>en</strong>sión .cpp, también conocidos como ficheros <strong>de</strong> implem<strong>en</strong>tación, ya que <strong>en</strong> ellos<br />
se <strong>de</strong>fin<strong>en</strong> las funciones y variables globales. Estos ficheros normalm<strong>en</strong>te ti<strong>en</strong><strong>en</strong> asociados unos<br />
ficheros <strong>de</strong> cabecera (con ext<strong>en</strong>sión .h), don<strong>de</strong> se <strong>de</strong>claran los miembros públicos. Es muy<br />
importante la disposición <strong>de</strong> los prototipos <strong>de</strong> las funciones públicas y las <strong>de</strong>claraciones <strong>de</strong> las<br />
estructuras públicas <strong>en</strong> las cabeceras, mi<strong>en</strong>tras que las respectivas implem<strong>en</strong>taciones <strong>de</strong>b<strong>en</strong> aparecer<br />
<strong>en</strong> los ficheros <strong>de</strong> implem<strong>en</strong>tación.<br />
/* punto.h */<br />
#ifn<strong>de</strong>f _PUNTO_H_<br />
#<strong>de</strong>fine _PUNTO_H_<br />
/** Estructura que repres<strong>en</strong>ta a puntos <strong>de</strong> dos dim<strong>en</strong>siones **/<br />
struct Punto {<br />
double x;<br />
double y;<br />
};<br />
/** Orig<strong>en</strong> <strong>de</strong> coor<strong>de</strong>nadas **/<br />
extern const Punto puntoOrig<strong>en</strong>;<br />
/** Creador <strong>de</strong> registros Punto<br />
* @param a La coor<strong>de</strong>nada horizontal<br />
* @param b La coor<strong>de</strong>nada vertical<br />
*/<br />
Punto crearPunto(double a, double b);<br />
/// @return la coor<strong>de</strong>nada horizontal<br />
double calculaDistancia(const Punto &p1, const Punto &p2);<br />
#<strong>en</strong>dif<br />
/* punto.cpp */<br />
#inclu<strong>de</strong> “punto.h”<br />
#inclu<strong>de</strong> <br />
const Punto PuntoOrig<strong>en</strong> = { 0, 0 };<br />
static double calculaDistanciaOrig<strong>en</strong>(const Punto &p1)<br />
/** Calcula distancia a orig<strong>en</strong> – Privada **/<br />
{<br />
return sqrt( ( p1.x * p1.x ) + ( p1.y * p1.y) );<br />
}
inline Punto crearPunto(double a, double b)<br />
{<br />
Punto p = { a, b };<br />
return p;<br />
}<br />
double calculaDistancia(const Punto &p1, const Punto &p2)<br />
{<br />
return abs( calculaDistanciaOrig<strong>en</strong>( p1 )<br />
– calculaDistanciaOrig<strong>en</strong>( p2 ) )<br />
;<br />
}<br />
La línea #ifn<strong>de</strong>f _PUNTO_H_ y la sigui<strong>en</strong>te lo que hac<strong>en</strong> es evitar que se compile la cabecera<br />
punto.h más <strong>de</strong> una vez. Ésto pue<strong>de</strong> suce<strong>de</strong>r inadvertidam<strong>en</strong>te <strong>en</strong> un proyecto complejo, cuando<br />
más <strong>de</strong> una cabecera incluye la primera. El diagnóstico <strong>de</strong> este problema es s<strong>en</strong>cillo, pues <strong>en</strong> ese<br />
caso el compilador se quejaría <strong>de</strong> una re<strong>de</strong>claración <strong>de</strong>l módulo Punto.<br />
Nótese que se ha incluido un objeto constante. Para po<strong>de</strong>r ser utilizado <strong>de</strong>be ser <strong>de</strong>clarado<br />
<strong>en</strong> el fichero <strong>de</strong> cabecera, con extern, si bi<strong>en</strong> nunca <strong>de</strong>finido (la cabecera pue<strong>de</strong> ser incluida <strong>en</strong><br />
varias unida<strong>de</strong>s <strong>de</strong> traducción: poner la <strong>de</strong>finición <strong>en</strong> la cabecera significaría que todas ellas<br />
t<strong>en</strong>drían un objeto puntoOrig<strong>en</strong> distinto, aunque con el mismo i<strong>de</strong>ntificador, lo que provocaría un<br />
error <strong>de</strong> <strong>en</strong>lace). La <strong>de</strong>finición, como pue<strong>de</strong> verse, aparece <strong>en</strong> el fichero <strong>de</strong> implem<strong>en</strong>tación,<br />
mi<strong>en</strong>tras que <strong>en</strong> el fichero <strong>de</strong> cabecera aparece una <strong>de</strong>claración con extern, <strong>de</strong> manera que el<br />
compilador sepa que está <strong>de</strong>finida <strong>en</strong> algún módulo (pero sólo <strong>en</strong> uno, claro, <strong>en</strong> otro caso se<br />
produce otro error).<br />
Si, <strong>en</strong> cambio, se <strong>de</strong>sea que un objeto no sea público, <strong>de</strong>be omitirse cualquier m<strong>en</strong>ción sobre<br />
él <strong>en</strong> la cabecera, y <strong>en</strong> el mom<strong>en</strong>to <strong>de</strong> la <strong>de</strong>finición <strong>en</strong> el archivo <strong>de</strong> implem<strong>en</strong>tación <strong>de</strong>be añadirse<br />
el modificador static (que <strong>en</strong> este caso <strong>de</strong> aplicación significa privado, y no ti<strong>en</strong>e, explícitam<strong>en</strong>te,<br />
el mismo significado que cuando se aplica a una variable local <strong>de</strong> una función).<br />
5.2 Funciones<br />
En las funciones, se <strong>de</strong>be adoptar como esquema básico la típica estructura inicialización<strong>de</strong>sarrollolimpieza,<br />
es <strong>de</strong>cir el comi<strong>en</strong>zo <strong>de</strong> la tarea, inicializando (y creando, cuando sea oportuno)<br />
las variables necesarias, el <strong>de</strong>sarrollo <strong>de</strong>l problema, como el bucle <strong>de</strong>l ejemplo situado más abajo,y<br />
finalm<strong>en</strong>te, cuando es necesario, la limpieza <strong>de</strong> los recursos utilizados.<br />
int sumaFicheroDatos(const char nombreFichero[])<br />
/**<br />
Lee el cont<strong>en</strong>ido <strong>de</strong> un archivo <strong>de</strong> texto, <strong>en</strong> el que cada línea es un<br />
número <strong>en</strong>tero, y lo suma.<br />
@param nombreFichero El nombre <strong>de</strong> fichero a cargar<br />
@return La suma <strong>de</strong> todos los valores <strong>en</strong> el fichero.<br />
**/<br />
{<br />
int num;<br />
int toret = 0;<br />
FILE * f = fop<strong>en</strong>( nombreFichero, “rt” );<br />
if ( f != NULL ) {<br />
fscanf( f, “%d\n”, &num );<br />
while( !feof( f ) ) {<br />
toret += num;<br />
fscanf( f, “%d\n”, &num );<br />
}<br />
fclose( f );
}<br />
}<br />
return toret;<br />
5.2.1 Estructuras <strong>de</strong> <strong>de</strong>cisión y repetición<br />
Es típico <strong>en</strong>contrarse con la necesidad <strong>de</strong> t<strong>en</strong>er que crear estructuras condicionales (if) o <strong>de</strong><br />
repetición (while), que se refier<strong>en</strong> a condiciones complejas. Debe tratarse, <strong>en</strong> estos casos, <strong>de</strong><br />
disponer una subcondición por línea, com<strong>en</strong>zando por el juntor (and (&&), or(||), y not(!)). Si es<br />
necesario, una subcondición pue<strong>de</strong> llevar un com<strong>en</strong>tario "a la <strong>de</strong>recha". Si exist<strong>en</strong> varias<br />
subexpresiones condicionales, se <strong>de</strong>b<strong>en</strong> in<strong>de</strong>ntar respecto a la expresión principal.<br />
if ( buffer != NULL<br />
&& feof( f )<br />
&& tamMaxBufferDestino > 0 )<br />
{<br />
while( !feof( f ) ) {<br />
/* más cosas ... */<br />
}<br />
}<br />
if ( feof( f )<br />
&& bytesLeidos > 0 )<br />
{<br />
memcpy( <strong>de</strong>st, buffer, tamMaxBufferDestino );<br />
}<br />
Cuando se crean estructuras <strong>de</strong> <strong>de</strong>cisión con más <strong>de</strong> una expresión condicional, no se <strong>de</strong>be<br />
utilizar la posibilidad <strong>de</strong> crear los cuerpos <strong>de</strong> instrucciones <strong>de</strong> una sola línea sin las llaves <strong>de</strong> inicio<br />
y fin <strong>de</strong> bloque ( { y } ), ya que la s<strong>en</strong>t<strong>en</strong>cia no sería visible, como se muestra a continuación.<br />
if ( feof( f )<br />
&& bytesLeidos > 0 )<br />
f.close();<br />
5.2.1.1 Cuerpos <strong>de</strong> instrucciones <strong>de</strong> una sola línea<br />
En g<strong>en</strong>eral, es más legible evitar esta posibilidad. Las s<strong>en</strong>t<strong>en</strong>cias <strong>de</strong> un bloque sin llaves casi pasan<br />
<strong>de</strong>sapercibidas, y por tanto es mejor cambiarlas por bloques siempre que sea posible. Recuér<strong>de</strong>se<br />
que los bloques <strong>de</strong> una sola línea sin llaves <strong>de</strong> comi<strong>en</strong>zo y fin son una posibilidad, no una<br />
obligación. En cuanto al espacio vertical, colocar la llave inicio <strong>en</strong> la misma línea <strong>de</strong> una s<strong>en</strong>t<strong>en</strong>cia<br />
<strong>de</strong> repetición o <strong>de</strong> <strong>de</strong>cisión (siempre que no haya múltiples subexpresiones condicionales), es una<br />
medida que pue<strong>de</strong> ser muy útil.<br />
En el caso <strong>de</strong> una s<strong>en</strong>t<strong>en</strong>cia ifth<strong>en</strong>else con sólo una expresión condicional, se pue<strong>de</strong> utilizar<br />
la posibilidad <strong>de</strong> los bloques sin llaves <strong>de</strong> comi<strong>en</strong>zo y fin, por ejemplo:<br />
int buscarPersona(const char nombre[], const Persona &vp[MaxPersonas])<br />
/**<br />
@param nombre vector <strong>de</strong> caracteres con el nombre a buscar<br />
@param vp vector <strong>de</strong> personas don<strong>de</strong> buscar<br />
@return<br />
*/<br />
{<br />
int i = 0;<br />
// Buscar <strong>en</strong> el nombre <strong>de</strong> cada persona<br />
for(; i < MaxPersonas; ++i) {<br />
if ( vp[ i ].nombre == nombre ) {<br />
break;
}<br />
}<br />
5.3 Espaciado<br />
}<br />
if ( i < MaxPersonas )<br />
return i;<br />
else return -1;<br />
El espaciado se refiere a separar ciertos elem<strong>en</strong>tos (operadores y paréntesis, principalm<strong>en</strong>te), <strong>de</strong> los<br />
argum<strong>en</strong>tos para que el conjunto sea más legible. El uso típico consiste <strong>en</strong> separar con un espacio<br />
los argum<strong>en</strong>tos <strong>en</strong> las listas <strong>de</strong> parámetros formales y <strong>de</strong> argum<strong>en</strong>tos, los corchetes <strong>de</strong>l operador <strong>de</strong><br />
subíndice, y los operadores como =, *. /, + y . Por ejemplo, compár<strong>en</strong>se las sigui<strong>en</strong>tes muestras:<br />
int x=a+b;<br />
int x = a + b;<br />
numRegistros=v.size()+registrosCabecera[i];<br />
numRegistros = v.size() + registrosCabecera[ i ];<br />
int z=elevarA(x,y);<br />
int z = elevarA( x, y );