3.1 Nomenclatura de las variables
Los nombres utilizados para las variables tienen que ser autoexplicativos. De manera que en el propio nombre
esté la indicación del uso o finalidad de las variables.
Para componer los nombres de las variables se utilizarán principalmente sustantivos, pudiendo
calificarse con adjetivos.
Esta norma se establece para mejorar la identificación de los distintos componentes de un sistema.
Una práctica muy habitual es utilizar una serie de prefijos para poder identificar el tipo de variable
de una forma sencilla y rápida. Este tipo de nomenclaturas se denomina notación húngara
(ideada por Charles Simonyi, arquitecto jefe de Microsoft, [2]).
Estos prefijos se añaden al nombre de la variable, sin separarlos de ninguna forma, como se muestra
en los ejemplos de la tabla.
Tipo |
Prefijo |
Ejemplo |
void |
v |
void vVariableVacia; |
bool |
b |
bool bOperacionValida; |
char |
c |
char cTeclaPulsada; |
int |
n |
int nNumeroCeldas; |
long |
l |
long lTotalUnidades; |
float |
f |
float fPrecioUnitario; |
double |
d |
double dAnguloMinimo; |
* (puntero) |
p |
int *pnMatrizValores; |
& (referencia(C++)) |
r |
float &rfMaximoAngulo |
[] (array) |
a |
double afRangosMaximos[3]; |
enum (enumeraciones) |
e |
EBoole eResultado; |
Como se ve en los mismos ejemplos indicados en esta tabla, se pueden utilizar varios de estos prefijos
en una misma definición.
Para el tema de cadenas de caracteres (strings, no confundir con la clase String), podríamos pensar que la
forma correcta de definirlas es, por ejemplo: char acNombrefichero[256+1];. Pero para poder identificarlas,
ya que se usan de manera estendida, podriamos usar el prefijo s. Por ejemplo:
// definición de una cadena de caracteres
char sNombreFichero [256+1];
|
De forma adicional, podríamos diferenciar la definición de una cadena de caracteres mediante el uso de []
(corchetes) (como en el ejemplo anterior) de la definición de un puntero a caracter (char *) que
contendría la dirección de memoria donde empieza esta cadena de caracteres.
// definición de un puntero a una zona de memoria que contiene una cadena
char *psPunteroAlNombre;
|
Estas dos definiciones se usan para esos casos, y quizás contradigan en parte la anterior norma de nomenclatura,
pero pueden ayudar a diferenciar las variables "cadena de caracteres" definidas por [] (corchetes) de
las definidas mediante char * (puntero a caracter), ya que pueden ser tratadas de manera muy diferente
por los compiladores, y la forma de utilizarlas por el programador es diferente.
Para otros tipos de variable no especificados en la tabla anterior no se establece prefijo, pero se puede
utilizar algún otro definido por otra norma o por el propio usuario.
Por ejemplo los siguientes:
Tipo |
Prefijo |
byte o unsigned char (uchar) |
by |
word o unsigned int (uint) |
w |
unsigned long (dword) |
dw |
handle (manejador, puntero de objetos de windows) |
h |
Para el contador de bucle for se pueden utilizar variables numéricas llamada i, j...
siempre que esto no perjudique en la comprensión del código (y estas variables se utilicen
solamente dentro del bucle del for).
Para estos casos (C++) se recomienda declarar la variable i en el propio bucle.
Ejemplo:
for (int i=0; i<strlen(sCadenaPrueba); i++) { ... }
|
[subir]
3.2 Utilización de variables
Todas las variables hay que declararlas en el ámbito más restringido posible.
Esto lleva a una utilización más eficiente de la pila y a una reducción de los
posibles errores por efectos "colaterales".
En general se aconseja limitar al máximo posible la visibilidad de las variables. Como norma general de
protección de datos.
Se debe evitar la conversión explícita de tipos de datos, ya que atenta contra la
comprobación de tipos de datos que hace el compilador.
Se aconseja utilizar la comversión implícita de tipos de datos cuando sea posible.
Se aconseja que cada variable se declare de forma separada.
Así se desaconseja una definicion como la siguiente:
// Multiple definición de variables, desaconsejada
int nContador, nNumeroFilas, nNumeroColumnas, nTotalElementos;
|
Mientras que lo correcto sería lo siguiente:
// Definición correcta de variables.
int nContador;
int nNumeroFilas;
int nNumeroColumnas;
int nTotalElementos;
|
Usar unsigned para variables que se sepa con seguridad que nunca van a tomar valores
negativos.
Es aconsejable que todas las variables sean inicializadas en la propia declaración de las mismas.
Por ejemplo:
// Definición más correcta de variables, con inicialización.
int nContador = 0;
int nNumeroFilas = 0;
int nNumeroColumnas = 0;
int nTotalElementos = 0;
|
[subir]
3.3 Variables locales
Las variables locales se deberían definir solamente en el bloque en el que se vayan a utilizar (en C++).
Así mejoraríamos el uso de la pila.
Las variables locales se deberían definir justo antes de su utilización (en C++).
De esta manera se evita el error habitual de tener variables definidas que luego no se utilizan.
[subir]
3.4 Variables globales
En general: NO UTILIZAR VARIABLES GLOBALES salvo en caso totalmente inevitable.
La existencia de variables globales atenta contra la comprensión del código y su encapsulamiento, además
de que puede provocar efectos "colaterales" inesperados (si una función varía el valor de la variable
global de forma no controlada) que desembocan en errores muy difíciles de identificar.
En el caso completamente inevitable de tener que utilizar variables globales, documentar ampliamente en los
ficheros y funciones que variables globales se van a utilizar, y cuales se van a modificar.
[subir]
3.5 Variables estáticas
Se recomienda minimizar el uso de variables estáticas, y solamente para casos en los que se
necesite "recordar" el estado de una función entre llamadas consecutivas a la misma.
No se deberían utilizar las variables estáticas como variables globales ocultas.
Las variables estáticas se tienen que inicializar en el momento en que se declaran, de
manera obligatoria.
[subir]
3.6 Inicialización de variables
Todas las variables hay que inicializarlas explícitamente antes de ser utilizadas, en especial las que se
alojan en la pila y las que obtienen espacio de almacenamiento de forma dinámica durante la ejecución.
De esta manera evitamos la ejecución de código con valores desconocidos de las variables, que provoca
el funcionamiento aleatorio del programa.
Las variables estáticas se tienen que inicializar en el momento en que se declaran.
[subir]
3.7 Asignación de memoria
Se aconseja el uso de new y delete para C++, en lugar de malloc, callod
y free (propios de C), ya que los operadores new y delete están especialmente
diseñados para trabajar con clases y llamar a los constructores y destructores (respectivamente) de las
mismas.
Siempre que se alloque memoria de manera dinámica (tanto con malloc y calloc (propios de
C) como con new (propio de C++)) hay que asegurarse de que el espacio requerido fué,
efectivamente, servido por el sistema operativo. Nunca se debería suponer que una asignación de memoria ha
terminado correctamente.
Si no se comprueba si se ha reservado correctamente la memoria se pueden obtener errores fatales, difíciles
de detectar en pruebas y difíciles de localizar.
Un ejemplo correcto es el siguiente:
char *psCadena = new char[24];
// se comprueba si se ha obtenido memoria realmente
if (0 == psCadena) return ERROR_RESERVA_MEMORIA;
...
|
Hay que liberar toda la memoria que se haya reservado de manera dinámica. No hay que esperar
que "algo" libere la memoria, hay que hacerlo explícitamente.
Si suna variable ya tiene asignada memoria de manera dinámica, hay que liberarla antes de cambiar
y asignarle nueva memoria.
Cuando se libere memoria con delete (C++) reservada para un array, hay que indicar el operador
[] (corchetes).
Esto se hace por legibilidad, y es obligatorio para algunos compiladores.
Así sería incorrecto indicar...
char *psCadena = new char[24];
...
delete psCadena; // Uso incorrecto de delete para un array
|
En cambio lo correcto seria indicar...
char *psCadena = new char[24];
...
delete [] psCadena; // Uso correcto de delete para un array
|
Cuando se libera memoria asignada dinámicamente (tanto con free (propio de C) como con
delete (propio de C++)) siempre se asignará a 0 el puntero superviviente.
De esta manera se minimizan los problemas que surgen de una mala gestión de memoria.
Por ejemplo:
delete pAuxiliar; // Liberamos memoria
pAuxiliar = 0; // asignamos a 0 el puntero resultante.
|
En el uso de punteros se desaconseja la comparación con NULL o la asignación a
NULL. Es preferible realizar la comparación con 0 o la asignación a
0.
NULL es un estandard ANSI-C definido como (void*)0 o 0. Si NULL
esta definido de tipo (void *) no se puede asignar arbitrariamente a otro tipo de puntero
sin utilizar una conversión explícita. Por esta razón es preferible utilzar
0 en asignaciones y comparaciones con punteros.
Ejemplo:
char *psCadena = 0;
... // unas cuantas líneas de código
psCadena = new char[24];
if (0 == psCadena) return ERROR_RESERVA_MEMORIA;
... // muchas líneas de código más adelante
delete psCadena;
psCadena = 0;
|
Se desaconseja el uso de punteros a punteros. Estas técnicas complican mucho la síntaxis
y la comprensión del código, pudiendo ser sustituidas utilizando otras técnicas.
[subir]
3.8 Cadenas de caracteres
Como se ha dicho anteriormente (notación húngara), en la definición de cadenas de
caracteres se puede utilizar el prefijo s o el prefijo ps, dependiendo del caso, para identificar el
tipo de variable, como por ejemplo:
char sNombreFichero [256+1]; // variable con zona de memoria ya reservada
char *sPunteroAlNombre; // puntero que apuntará a una cadena en memoria
|
La memoria necesaria para almacenar una cadena de N caracteres se definirá como una zona de memoria
para N+1 caracteres.
La posición número N+1 es la del caracter "\0" o de fin de cadena (hay que tener en cuenta
que la primera posición es la número 0).
Esta regla resultará muy util para evitar confusiones por el caracter "extra" que supone el caracter
fin de cadena.
Por ejemplo, para el siguiente código:
char sMiCadena[4+1];
sprintf (sMiCadena, "hola");
|
la variable sMiCadena contendría lo siguiente:
caracter -> |
h |
o |
l |
a |
\0 |
posición -> |
0 |
1 |
2 |
3 |
4 |
[subir]
|