• ERRORES COMUNES DE PROGRAMACIÓN • BUENAS

Anuncio
MIGUEL Á. TOLEDO MARTÍNEZ
• ERRORES COMUNES DE PROGRAMACIÓN
• BUENAS PRÁCTICAS DE PROGRAMACIÓN
• PROPUESTAS DE DESEMPEÑO
• SUGERENCIAS DE PORTABILIDAD
• OBSERVACIONES DE INGENIERÍA DE SOFTWARE
• INDICACIONES DE PRUEBA Y DEPURACIÓN
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-1
MIGUEL Á. TOLEDO MARTÍNEZ
ERRORES COMUNES DE PROGRAMACIÓN
Bajo el título de buenas prácticas de programación se incluirán muchas sugerencias a
lo largo de las lecciones para subrayar las prácticas que ayudarán a escribir programas
más claros, comprensibles y fáciles de mantener, probar y depurar. Estas prácticas son
sólo guías; sin duda usted desarrollará su propio estilo de programación. También
subrayaremos varios errores comunes de programación (problemas que prever para
evitar caer en estos errores en sus programas), consejos de desempeño (técnicas que le
ayudarán a escribir programas más rápidos y de menor consumo de memoria),
explicaciones de portabilidad (técnicas que le ayudarán a escribir programas que
puedan ejecutarse con pocos o ningún cambio en diferentes tipos de computadora),
observaciones sobre ingeniería de software (ideas y conceptos que afectan y mejoran la
arquitectura general de un sistema de software y, en particular, en el caso de los
sistemas de software grandes), así como indicaciones de prueba y depuración
(sugerencias para probar sus programas y ayudarle a aislar y eliminas bugs)
1.
2.
3.
4.
5.
6.
Los errores como la división entre cero suceden durante la ejecución del programa, por lo que se
llaman errores en tiempo de ejecución. La división entre cero por lo general es un error fatal, es
decir, un error que provoca que el programa termine de inmediato sin haber concluido de manera
apropiada su trabajo. Los errores no fatales permiten que los programas se ejecuten hasta el fin,
generalmente produciendo resultados incorrectos. (Nota: en algunos sistemas, la división entre cero
no es un error fatal. Lea la documentación del sistema con el que esté trabajando).
Si olvida incluir el archivo iostream.h en un programa que acepta entrada desde el teclado o envía
datos a la pantalla, el compilador emitirá un mensaje de error.
La omisión del punto y coma al final de una instrucción es un error de sintaxis. Los errores de
sintaxis se producen cuando el compilador no puede reconocer una instrucción. El compilador
normalmente emite un mensaje de error que ayuda al programador a localizar y corregir la
instrucción incorrecta. Los errores de sintaxis son violaciones al lenguaje. También se les conoce
como errores de compilación y errores en tiempo de compilación, debido a que aparecen durante la
fase de compilación.
Si intenta utilizar el operador de módulo, %, con operandos que no son enteros, se producirá un error
de sintaxis.
Si cualquiera de los operadores ==, !=, >= y <= aparece con espacios entre el par de símbolos,
sucederá un error de sintaxis.
La inversión del orden del par de operadores de los operadores !=, >= y <= (al escribirlos como =!,
=> o =<) normalmente es un error de sintaxis. En algunos casos, escribir != como =! no será un
error de sintaxis, pero casi con toda seguridad será un error de lógica.
No confunda el operador de igualdad == con el operador de asignación =. El primero debe leerse
como es igual que y el segundo como obtiene, obtiene el valor de o se le asigna el valor de. Algunas
personas prefieren leer el operador de igualdad como doble igual. Como veremos pronto, la
confusión de estos operadores no necesariamente causa un error de sintaxis fácil de reconocer, pero
puede provocar errores muy sutiles de lógica.
8. Es un error utilizar el operador AND lógico (&&) en vez del operando AND a nivel de bits (&) y
viceversa.
9. Utilizar el operador OR lógico ( || ) en vez del operador OR a nivel de bits ( | ) y viceversa.
10. El resultado del desplazamiento de un valor es indefinido si el operando derecho es negativo o si el
operando derecho es más grande que el número de bits en los que está almacenado el operando
izquierdo.
7.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-2
MIGUEL Á. TOLEDO MARTÍNEZ
11. Las funciones de manipulación de cadenas diferentes a memmove() que copian caracteres tienen
resultados indefinidos cuando el copiado se realiza entre partes de la misma cadena.
12. La colocación de un punto y como (;) justo después del paréntesis derecho tras la condición de una
estructura if con frecuencia es un error de lógica (aunque no un error de sintaxis). El punto y coma
provocará que el cuerpo de la estructura if esté vació,, por lo que la estructura misma no llevaría a
cabo ninguna acción, sin importar si la condición es verdadera o no. Peor aún, la instrucción original
del cuerpo de la estructura if ahora se volverá una instrucción en secuencia con la estructura if y
siempre se ejecutará, causando muchas veces que el programa genere resultados incorrectos.
13. Dividir los identificadores insertando caracteres de espacios en blanco (por ejemplo, escribiendo
main como ma in) es un error de sintaxis.
14. El empleo de una palabra reservada como identificador es un error de sintaxis.
15. Si olvida una o ambas llaves delimitadoras de una instrucción compuesta, pueden producirse errores
de sintaxis o de lógica en el programa.
16. Un punto y coma tras la condición de una estructura if genera un error de lógica en las estructuras if
de selección única y un error de sintaxis en las estructuras if de doble selección (si la parte if
contiene una instrucción en su cuerpo).
17. Si no se indica en el cuerpo de una estructura while una acción que en algún momento provoque que
la condición se vuelva false, lo común es que se presente un error llamado ciclo infinito, en el que la
estructura de repetición nunca termina.
18. La palabra reservada while no se debe escribir con W mayúscula (como While), ya que es un error de
sintaxis (recuerde que C++ es un lenguaje sensible a las mayúsculas y minúsculas). Todas las
palabras reservadas de C++, como while, if y else, sólo utilizan minúsculas.
19. Si los contadores y totales no se inicializan, el resultado del programa probablemente sea incorrecto.
Este es un ejemplo de error de lógica.
20. En los ciclos controlados por contador, debido a que el contador de ciclo tiene un valor mayor en uno
que su último valor legítimo (es decir 11, en el caso de que se esté contando del 1 al 10), es común
que, si se toma el valor del contador para efectuar un cálculo tras terminar el ciclo, se genere un
error por diferencia de uno.
21. La selección de un valor centinela que también es un valor de datos válido es un error de lógica.
22. Los intentos por dividir entre cero causan errores fatales.
23. El uso de números de punto flotante de una manera que suponga que se representan con precisión
puede dar resultados incorrectos. La mayoría de las computadoras sólo representan de manera
aproximada a los números de punto flotante.
24. Utilizar el operador de incremento o decremento en una expresión que no sea un nombre de variable
simple (por ejemplo, ++(x+1)) es un error de sintaxis.
25. Dado que los valores de punto flotante pueden ser aproximados, el control de los ciclos con contador
mediante variables de punto flotante puede dar como resultado valores de contador imprecisos y
pruebas de terminación incorrectas.
26. El empleo de un operador relacional incorrecto o de un valor final de contador de ciclo equivocado
en la condición de una estructura while o for puede provocar errores por diferencia de uno.
27. Cuando la variable de control de una estructura for se define desde el principio en la sección de
iniciación del encabezado de la estructura for, el empleo de la variable de control fuera del cuerpo de
la estructura es un error de sintaxis.
28. Indicar comas en lugar de los dos puntos y coma en el encabezado for es un error de sintaxis.
29. Un punto y coma inmediatamente a la derecha del paréntesis derecho de un encabezado for hace que
el cuerpo de dicha estructura sea una instrucción vacía. Comúnmente éste es un error de lógica.
30. No emplear el operador relacional adecuado para la condición de continuación de un ciclo que
cuenta hacia abajo (como cuando se utiliza incorrectamente i <= 1 en un ciclo que cuenta hacia abajo
hasta 1) podría generar un error de lógica que produciría resultados incorrectos al ejecutarse el
programa.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-3
MIGUEL Á. TOLEDO MARTÍNEZ
31. Si no se incluye el archivo math.h en un programa que maneje funciones de la biblioteca matemática
se generará un error de sintaxis.
32. Olvidar una instrucción break cuando es necesaria en una instrucción switch es un error de lógica.
33. La omisión del espacio entre la palabra case y el valor entero que se está probando en una estructura
switch puede provocar un error de lógica. Por ejemplo, escribir case3: en lugar de case 3:
simplemente crea una etiqueta no usada. El problema es que la estructura switch no efectuará las
acciones correctas cuando la expresión de control del switch tenga un valor de 3.
34. Si no se procesan los caracteres de salto de línea y otros caracteres de espacio en blanco que
aparecen en la entrada durante la lectura de caracteres uno por uno, es posible que sucedan errores
de lógica.
35. Indicar varias etiquetas case iguales en una estructura switch es un error de programación.
36. Los ciclos infinitos suceden cuando la condición de continuación del ciclo de una estructura while,
for o do/while nunca se vuelve false. Para evitarlos, asegúrese de que el valor de la condición
cambie en algún lugar del encabezado o del cuerpo del ciclo, para que la condición pueda, en algún
momento volverse false.
37. Aunque 3 < x < 7 es una condición matemáticamente correcta, en C++ no se evalúa correctamente.
Para obtener en C++ la evaluación correcta, utilice (3 < x && x < 7)
38. En las expresiones que utilizan el operador &&, es posible que una condición (a la que llamaremos
condición dependiente) requiera que otra condición sea true para que tenga sentido evaluar la
condición dependiente. En este caso, dicha condición debe ponerse tras la otra condición o podría
suceder un error.
39. Emplear el operador == para realizar una asignación o utilizar el operador = para realizar una
igualdad son errores de lógica.
40. Es un error tratar de leer de un ostream (o de cualquier otro flujo de sólo salida)
41. Es un error tratar de escribir a un istream (o a cualquier otro flujo de sólo entrada)
42. Es un error no colocar paréntesis para forzar la precedencia adecuada cuando se utiliza el operador
de inserción de flujo << o el operador de extracción de flujo >> que tienen una precedencia
relativamente alta.
43. El establecimiento de anchura se aplica sólo para la siguiente inserción o extracción. Después de ello
la anchura se establece implícitamente a 0, es decir, los valores de salida serán tan anchos como
necesiten serlo. La función width sin argumentos devuelve el valor actual. Suponer que el
establecimiento de anchura se aplica a todas las salidas es un error de lógica.
44. Cuando no se proporciona un campo lo suficientemente ancho para manejar las salidas, éstas se
imprimirán tan anchas como necesiten serlo lo que causará, posiblemente, que sean difíciles de leer.
45. Es un error abrir un archivo existente para salida (ios::out) cuando, de hecho, el usuario quiere
conservar dicho archivo, ya que el contenido de éste se descarta sin aviso alguno.
46. El uso de un objeto ofstream incorrecto para referirse a un archivo.
47. Es un error no abrir un archivo antes de intentar referenciarlo en un programa.
BUENAS PRÁCTICAS DE PROGRAMACIÓN
1.
2.
3.
Escriba sus programas de C++ sencillo y directamente. Esto a veces se conoce como mantelo simple.
No estire el lenguaje intentando usos raros.
Lea los manuales de la versión de C++ que esté empleando. Consulte estos manuales con frecuencia
para asegurar que tenga presente el rico conjunto de características de C++ y que esté empleando
correctamente estas características.
Su computadora y su compilador son buenos maestros. Si tras la lectura de su manual del lenguaje
C++ no está seguro del funcionamiento de alguna característica de C++, experimente con un
pequeño programa de prueba y vea lo que sucede. Ajuste las opciones de su compilador para que le
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-4
MIGUEL Á. TOLEDO MARTÍNEZ
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
devuelva el máximo de avisos. Estudie cada mensaje que aparezca al compilar sus programas y
corríjalos para eliminar los mensajes.
Cada programa debe comenzar con un comentario que describa su propósito.
Muchos programadores hacen que el último carácter impreso por una función sea un saldo de línea
(\n) Esto asegura que la función dejará el cursor al inicio de una nueva línea. Las convenciones de
esta naturaleza promueven la reutilización del software, meta clave en los entornos de desarrollo de
software.
Dentro de los corchetes que definen el cuerpo de una función, sangre el cuerpo de la función un
nivel. Esto resalta la estructura funcional de los programas y ayuda a simplificar su lectura.
Establezca una convención para el tamaño de las sangrías y luego aplíquela de manera uniforme. La
tecla Tab sirve para crear sangrías, pero las tabulaciones pueden variar. Recomendamos manejar
tabulaciones de ¼ de pulgada o (de preferencia) de tres espacios por cada nivel de sangría.
Algunos programadores prefieren declarar las variables en líneas separadas. Este formato permite la
fácil inserción de comentarios descriptivos junto a cada declaración.
Para hacer más legibles sus programas, ponga espacios después de las comas (, )
La declaración de variables con nombres significativos ayuda a que los programas estén auto
documentados, es decir, que resulte más fácil entenderlos simplemente leyéndolos en lugar de tener
que consultar manuales o hacer referencia a demasiados comentarios.
Evite los identificadores que comiencen con uno o dos caracteres de subrayado, pues podría ser que
el compilador de C++ utilice nombres de este tipo para fines internos. Esto evitará que los nombres
que usted determine se confundan con los nombres que el compilador seleccione.
Siempre inserte una línea en blanco antes de una declaración que aparezca entre instrucciones
ejecutables. Esto resalta las declaraciones y contribuye a la claridad del programa.
Si prefiere poner declaraciones al inicio de una función, sepárelas de las instrucciones ejecutables de
la función por medio de una línea en blanco que resalte el punto donde terminan las declaraciones e
inician las instrucciones ejecutables.
Ponga espacios en ambos lados de los operadores binarios. Con esto se resalta el operador y se
simplifica la lectura del programa.
Como en álgebra, para hacer más clara a una expresión es aceptable agregarle paréntesis
innecesarios. Dichos paréntesis se llaman paréntesis redundantes. Estos se emplean normalmente
para agrupar subexpresiones de expresiones más grandes.
Sangre la instrucción del cuerpo de una estructura if para que resalte la estructura y simplificar la
lectura del programa.
En los programas no debe haber más que una instrucción por línea.
Es posible distribuir una instrucción grande sobre varias líneas. Si tiene que dividir una instrucción
sobre varias líneas, seleccione puntos de ruptura que tengan sentido, como después de una coma en
el caso de una lista separada por comas o después de un operador en el caso de una expresión larga.
Si necesita dividir una instrucción en varias líneas, sangre todas las líneas subsecuentes.
Al escribir expresiones que contengan muchos operadores, consulte la tabla de precedencia de los
operadores. Confirme que los operadores de la expresión se ejecutan en el orden que espera. Si no
está seguro del orden de evaluación de una expresión compleja, coloque paréntesis para forzar el
orden, justo igual como lo haría en una expresión algebraica. Además, observe que algunos
operadores, como el de asignación (=), se asocian de derecha a izquierda, y no de izquierda a
derecha.
La consistencia en la aplicación razonable de convenciones de sangrado a sus programas simplificará
notablemente su lectura. Sugerimos una tabulación fija de ¼ de pulgada o tres espacios en blanco por
cada sangría.
El seudo código se emplea con frecuencia para pensar el programa durante el proceso de diseño.
Luego el programa en seudo código se convierte a su equivalente en C++.
Sangre las instrucciones de ambos cuerpos de las estructuras if/else.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-5
MIGUEL Á. TOLEDO MARTÍNEZ
23. Si hay varios niveles de sangrado, todos deben sangrarse con espacios iguales.
24. Siempre ponga llaves en las estructuras if/else (y en cualquier estructura de control) para ayudarle a
evitar su omisión accidental, especialmente si después le agrega instrucciones a una cláusula if o
else.
25. Algunos programadores prefieren colocar primero las llaves izquierda y derecha y después introducir
las instrucciones que van dentro de ellas. Con esto se evita la omisión de alguna de dichas llaves.
26. Inicialice los contadores y totales.
27. Declare cada variable en una línea diferente.
28. Al efectuar divisiones entre una expresión cuyo valor podría ser cero, busque explícitamente esta
condición y manéjela de manera adecuada (imprimiendo un mensaje de error) en lugar de permitir
que suceda el error fatal.
29. Mediante un mensaje pídale al usuario todas las entradas de teclado. Dicho mensaje debe especificar
la forma de la entrada y los valores especiales que pueda tener (como el valor centinela que debe
indicar el usuario para terminar algún ciclo)
30. En los ciclos controlados por un valor centinela, las solicitudes de entrada de información deben
recordarle explícitamente al usuario dicho valor centinela.
31. No compare la igualdad o desigualdad de los valores de punto flotante. En cambio, pruebe que el
valor absoluto de la diferencia sea menor que un valor pequeño especificado.
32. La iniciación de variables cuando se declaran ayuda al programador a evitar los problemas
provocados por datos no inicializados.
33. Los operadores unarios deben ponerse junto a sus operandos, sin espacios intermedios.
34. Controle los ciclos con contadores por medio de variables enteras.
35. Sangre las instrucciones del cuerpo de cada estructura de control
36. Ponga una línea en blanco antes y después de cada estructura de control, con el fin de resaltarlas en
el programa.
37. Si hay demasiados niveles de anidamiento puede volverse difícil entender el programa. Como regla
general, trate de evitar codificar más de tres niveles de sangrado.
38. El espaciado vertical de las estructuras de control, así como el sangrado de los cuerpos de las
estructuras de control dentro de sus encabezados, le da al programa una apariencia bidimensional que
simplifica en gran medida su lectura.
39. Para ayudarle a evitar los errores por diferencia de uno, utilice el valor final en la condición de una
estructura while o for y el operador relacional <=. Por ejemplo, para un ciclo que imprime los
valores 1 a 10, la condición de continuación del ciclo debería ser contador <= 10, en lugar de
contador < 10 (lo que es un error por diferencia de uno) o contador < 11 (que, sin embargo, es
correcta) No obstante, muchos programadores prefieren el llamado conteo basado en cero, en el que
para contar 10 veces, habría que inicializar contador a cero y la prueba de continuación del ciclo
sería contador < 10.
40. En las secciones de iniciación e incremento de las estructuras for sólo ponga expresiones
relacionadas con las variables de control. Las manipulaciones de otras variables deben aparecer antes
del ciclo (si sólo se ejecutan una vez, como las instrucciones de inicialización) o en el cuerpo del
ciclo (si se ejecutan una vez por repetición, como en el caso de las instrucciones de incremento o
decremento)
41. Aunque el valor de la variable de control puede cambiarse en el cuerpo del ciclo for, evite hacerlo,
pues esta práctica puede generar sutiles errores de lógica.
42. Aunque las instrucciones que preceden a un ciclo for y las del cuerpo de éste con frecuencia pueden
insertarse en el encabezado del for, evite hacerlo, pues podría hacer más difícil la lectura del
programa.
43. De ser posible, limite a una sola línea el tamaño de los encabezados de las estructuras de control.
44. No emplee variables de tipo float o double para efectuar cálculos monetarios. La imprecisión de los
números de punto flotante puede provocar errores que generarán valores monetarios incorrectos.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-6
MIGUEL Á. TOLEDO MARTÍNEZ
45.
46.
47.
48.
49.
50.
Nota: están apareciendo bibliotecas de clases de C++ para manejar adecuadamente los cálculos
monetarios.
Agregue un caso default en las instrucciones switch. Los casos no probados explícitamente en una
instrucción switch que no tenga un caso default son ignorados. Al incluir el caso default se enfoca al
programador en la necesidad de procesar condiciones excepcionales. Hay situaciones en las que no
es necesario el procesamiento default.
Aunque las cláusulas case y el caso default de la estructura switch pueden suceder en cualquier
orden, se considera una buena práctica de programación poner la cláusula default al último.
En las estructuras switch, cuando la cláusula default se lista al último, no es necesaria la instrucción
break. Algunos programadores incluyen este break por claridad y simetría con los demás case.
Algunos programadores siempre incluyen llaves en las estructuras do/while, incluso cuando no son
necesarias. Esto ayuda a eliminar las ambigüedades entre la estructura while y la estructura do/while
que contiene una sola instrucción.
Algunos programadores sienten que break y continue violan la programación estructurada. Y no las
utilizan debido a que los efectos de estas instrucciones pueden lograrse por medio de técnicas de
programación estructurada.
En los programas C++ utilice exclusivamente la forma de E/S de C++, a pesar de que los
programadores de C++ tienen disponible la E/S estilo C.
51. Cuando envíe a la salida expresiones, colóquelas entre paréntesis para impedir problemas de
precedencia de operadores entre los operadores de la expresión y el operador <<.
52. Abra un archivo un archivo para entrada (utilizando ios::in) solamente si el contenido del archivo no
debe ser modificado. Esto impide una modificación no intencional del contenido del archivo. Este es
un ejemplo del principio de menor privilegio.
PROPUESTAS DE DESEMPEÑO
1.
2.
3.
4.
5.
6.
7.
8.
Utilizar las funciones y clases de la biblioteca estándar, en lugar de escribir sus propias versiones
comparables, puede mejorar el desempeño de sus programas, debido a que han sido escritas
cuidadosamente para que su desempeño sea eficiente.
La estructura if/else anidada puede ser mucho más rápida que una serie de estructuras if de selección
única, pues existe la posibilidad de salir con rapidez de la estructura una vez que se satisfacen las
condiciones.
En la estructura ilf/else, pruebe hacia el principio de la estructura las condiciones que más
probablemente sean true. Esto permite que dicha estructura se ejecute con mayor rapidez y salga
antes que en los casos que suceden con menos frecuencia.
Cuando se emplean operadores de asignación abreviados, los programadores pueden escribir sus
programas con un poco más de rapidez y los compiladores pueden compilar los programas a una
velocidad un poco mayor. Algunos compiladores generan códigos que se ejecuta más rápido cuando
se utilizan dichos operadores.
Muchos de las propuestas de desempeño que mencionados en estas lecciones generan mejoras
marginales, por lo que el lector podría estar tentado a ignorarlos. Sin embargo, cuando se pone una
mejora supuestamente marginal en un ciclo que se repite muchas veces, se suele lograr un mejor
desempeño.
Evite poner dentro de los ciclos expresiones cuyos valores no cambien. Pero si lo hace, muchos de
los compiladores refinados optimizadores actuales colocarán automáticamente tales expresiones
fuera de los ciclos, cuando se genere el código de lenguaje de máquina.
Muchos compiladores contienen características de optimización que mejorar el código que usted
escribe, pero sigue siendo mejor que escriba un buen código desde el principio.
En situaciones en las que la prioridad es el desempeño y donde la memoria es escasa o la velocidad
de ejecución es crucial, podría ser necesario manejar enteros pequeños.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-7
MIGUEL Á. TOLEDO MARTÍNEZ
9.
10.
11.
12.
13.
Utilizar enteros de tamaño pequeño puede provocar la ejecución más lenta del programa si las
instrucciones de la máquina que los manipulan no son tan eficientes como aquéllas que manipulan
los enteros de tamaño natural (por ejemplo, cuando debe efectuarse la extensión del signo en ellos)
Las instrucciones break y continue bien empleadas se ejecutan más rápido que sus técnicas
estructuradas correspondientes.
En las expresiones que utilizan el operador &&, si las condiciones individuales son independientes
entre ellas, haga que la condición que más probablemente sea false quede a la izquierda. En las
expresiones que utilizan el operador ||, haga que la condición que más probablemente sea true sea la
de la izquierda. Con esto es posible reducir el tiempo de ejecución del programa.
Utilice la E/S sin formato para obtener el mejor desempeño en el procesamiento de archivos de alto
volumen.
Cierre explícitamente cada archivo tan pronto como sepa que el archivo ya no volverá a hacer
referencia al mismo. Esto puede reducir el uso de recursos de un programa que continuará
ejecutándose después de que ya no necesite un archivo particular. Esta práctica también mejora la
claridad del programa.
SUGERENCIAS DE PORTABILIDAD
1.
2.
3.
4.
5.
6.
7.
8.
9.
Debido a que C es un lenguaje estandarizado, independiente del hardware y ampliamente difundido,
es frecuente que las aplicaciones escritas en C puedan ejecutarse con pocas o ninguna modificación
en un gran rango de sistemas de cómputo.
El empleo de funciones y clases de la biblioteca estándar, en lugar de escribirlas usted mismo, puede
mejorar la portabilidad de los programas, debido a que dicho software está incluido en prácticamente
todas las implementaciones de C++.
Aunque es posible escribir programas portables, hay muchos problemas entre los distintos
compiladores de C y C++ y las distintas computadoras que pueden hacer difícil lograr la
portabilidad. El simple hecho de escribir programas en C y C++ no lo garantizan. El programador
con frecuencia tendrá que encarar directamente las variaciones entre compiladores y computadoras.
C++ permite identificadores de cualquier longitud, pero el sistema y/o tipo de implementación de
C++ podrían aplicar algunas restricciones a la longitud de los identificadores. Utilice identificadores
de 31 caracteres o menos, para asegurar la portabilidad.
Las manipulaciones de datos al nivel de bits son dependientes de la máquina.
El resultado de desplazar a la derecha un valor con signo depende de la máquina. Algunas máquinas
rellanan con ceros y otras utilizan el bit de signo.
El tipo size_t es un alias dependiente del sistema para el tipo unsigned long o el tipo unsigned int.
El mensaje que strerror() genera es dependiente del sistema.
En el nuevo estándar preliminar de C++, el alcance de la variable de control declarada en la sección
de inicialización de una estructura for es diferente del alcance en los compiladores de C++
anteriores,. El código C++ creado con los viejos compiladores de C++ podría fallar al compilarse en
los compiladores que son compatibles con el estándar preliminar de C++. Las siguientes son dos
estrategias de defensa para evitar este problema: defina las variables de control con nombres
diferentes en cada estructura for o, si prefiere emplear el mismo nombre para las variables de control
de varias estructuras for, defina la variable de control fuera y antes del primer ciclo for.
10. Las combinaciones de teclas para dar el fin de archivo son dependientes del sistema.
11. Probar por la constante simbólica EOF en lugar de –1 hace a los programas más portables. El
estándar ANSI indica que EOF es un valor entero negativo (pero no necesariamente –1) Por lo tanto,
EOF podría tener valores diferentes, según el sistema.
12. Dado que el tamaño de los int varía según el sistema, emplee enteros long si espera procesar enteros
que caigan fuera del rango ±32767 y si desea ejecutar el programa en diferentes sistemas de
cómputo.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-8
MIGUEL Á. TOLEDO MARTÍNEZ
13. Por compatibilidad con las versiones anteriores de estándar C++, el valor booleano true también
puede representarse mediante cualquier valor distinto de cero y el valor booleano false como 0.
14. Cuando le indique al usuario cómo terminar la entrada desde el teclado, pídale que teclee un fin de
archivo para terminar la entrada, en vez de pedirle <ctrl>d (para UNIX y Macintosh) o <ctrl>z (PC
y VAX).
OBSERVACIONES DE INGENIERÍA DE SOFTWARE
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
Utilice un enfoque de bloques de construcción para crear programas. Evite reinventar la rueda.
Utilice las partes existentes donde sea posible; a esto se le llama reutilización de software, lo cual es
crucial en la programación orientada a objetos.
Al programar en C++, normalmente utilizará los siguientes bloques de construcción: clases y
funciones de la biblioteca estándar de C++, clases y funciones creadas por usted mismo y clases y
funciones de diversas bibliotecas no estándar comunes.
Cualquier programa en C++ puede construirse con los siete tipos de estructuras de control: if, if/else,
switch, while, do/while y for, combinándolas únicamente de dos maneras (apilamiento de estructuras
de control y anidamiento de estructuras de control)
Las instrucciones compuestas pueden ponerse en cualquier lugar del programa en el que pueda ir una
instrucción sencilla.
Así como pueden ponerse instrucciones compuestas en cualquier lugar donde pueda ir una
instrucción sencilla, también es posible no tener ninguna instrucción, es decir, tener una instrucción
vacía. Esta se representa poniendo un punto y coma (;) donde normalmente iría una instrucción.
Cada refinamiento, así como la parte superior misma, es una especificación completa del algoritmo;
lo que varía es el nivel de detalle.
Muchos programas pueden dividirse lógicamente en tres fases: Una de inicio, que inicializa las
variables del programa; otra de procesamiento, que acepta los datos de entrada y ajusta las variables
de programa correspondientes; y otra de terminación, que calcula e imprime el resultado final.
El programador termina el proceso de refinamiento descendente paso a paso cuando especifica el
algoritmo con el detalle suficiente para poder convertir el seudo código en código de C++; a partir de
aquí, la implementación del programa en C++ suele ser directa.
La experiencia ha mostrado que la parte más difícil de resolver un problema en una computadora es
desarrollar el algoritmo de solución. Una vez que se ha especificado un algoritmo correcto, el
proceso de generación de un programa C++ funcional a partir de dicho algoritmo suele ser directo.
Muchos programadores experimentados escriben programas sin emplear herramientas de desarrollo
como el seudo código. Estos programadores sienten que su meta es revolver el problema en la
computadora y que la escritura del seudo código simplemente retrasa la obtención de resultados.
Aunque esto podría funcionar en el caso de problemas sencillos y conocidos, puede provocar errores
serios y retrasar proyectos grandes y complejos.
A veces se pone un punto y como justo después de un encabezado for para crear un ciclo de retardo.
Tal ciclo for con un cuerpo vacío efectúa la cantidad indicada de ciclos sin hacer nada más que
contar. Puede utilizar un ciclo de retardo, por ejemplo, para reducir la velocidad de un programa que
genera salidas a la pantalla a una velocidad demasiado alta para poderlas leer.
Existe un conflicto entre conseguir una ingeniería de software de calidad y lograr el mejor
desempeño del software. Es frecuente que se logre una de estas metas a expensas de la otra.
El estilo de E/S de C++ es a prueba de tipos.
C++ permite un tratamiento común de la E/S de tipos predefinidos y tipos definidos por el usuario.
Este tipo de comunidad facilita el desarrollo de software en general y la reutilización del software en
particular.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-9
MIGUEL Á. TOLEDO MARTÍNEZ
INDICACIONES PARA PRUEBA Y DEPURACIÓN
1.
Los programadores normalmente escriben condiciones como x == 7 con el nombre de la variable a la
izquierda y la constante a la derecha. Si el programador las invierte de modo que la constante esté a
la izquierda y el nombre de la variable a la derecha como en 7 == x, el reemplazo accidental del
operador == con = quedará protegido por el compilador. Este tratará esto como error sintáctico, pues
a la izquierda de una instrucción de asignación sólo se puede poner un nombre de variable. Esto
cuando menos evitará el desastre potencial de un error de lógica en tiempo de ejecución.
2.
Utilice su editor de texto para buscar todas las apariciones de = en el programa y comprueba que
cada operador esté en el lugar correcto.
SUGERENCIAS, OBSERVACIONES Y CONSEJOS: PRIMERA PARTE
SUGERENCIAS-10
Descargar