Manual de estilo C / C++

[< anterior]       [indice]       [siguiente >]

2. Sobre el código


2.1 Líneas

  • Es aconsejable no utilizar más de una instrucción por línea de código. Para conservar la legibilidad del mismo

    Por ejemplo, la siguiente línea no es muy clara:

    nValor=nA*2; nValor2=nA+12; nValor3=nValor+nValor2;
    // esto puede producir errores de interpretación.

    Queda más claro de la siguiente manera:

    nValor  = nA*2;
    nValor2 = nA+12;
    nValor3 = nValor+nValor2;
    // ahora están más claras las diferentes asignaciones.

  • Las líneas de código no deberían ser superiores a 80 caracteres, que es el tamaño de línea habitual en editores de texto plano de sistemas operativos como Unix y Linux.

    Muchas emulaciones y algunos editores no soportan más de 80 caracteres por línea. Lineas mayores provocarían incomodidad al revisar el código (ya que las líneas aparecerían partidas), pudiendo dar lugar a posibles errores en la interpretación.

[subir]

2.2 Indentación o sangrado

  • Es aconsejable que el código esté indentado, de una forma adecuada y consistente. La indentación (o sangrado) ayuda a ver la estructura del programa y falicita la identificación de posibles errores
    Existen multitud de editores y formateadores de código que ayudan en esta tarea, pero es aconsejable ir haciendo la indentación sobre la marcha.

    Al indentar (o sangrar) el código se presenta de una manera clara la agrupación en bloques del programa, consiguiendo que sea más sencillo relacionar las llaves de cierre con sus correspondientes llaves de apertura.

    El siguiente trozo de código puede dar problemas en su comprensión:

    for (i=0; i<nMaximo; i++)
    {
    if (bValor)
    {
    hazOperacionParcial();
    ponResultadoParcial ();
    if (i > nMedio)
    {
    hazOperacionMayorMedio ();
    ponResultadoMayorMedio ();
    }
    }
    ponSiguienteResultado ();
    }
    // Al no haber sangrado parece que sobran llaves de cierre.
    // o no se sabe muy bien cuando se ejecutan las funciones.

    Queda más claro de la siguiente manera:

    for (i=0; i<nMaximo; i++)
      {
        if (bValor)
          {
            hazOperacionParcial();
            ponResultadoParcial ();
            if (i > nMedio)
              {
                hazOperacionMayorMedio ();
                ponResultadoMayorMedio ();
              }
          }
        ponSiguienteResultado ();
      }
    // Con el sangrado queda muy clara la agrupación en bloques del código.

[subir]

2.3 Bloques

  • Deben utilizarse llaves para delimitar todos los bloques de sentencias de control y bucles.
    Las llaves deben estar en la misma columna (y preferentemente solos, sin código ejecutable).

  • Habitualmente puede resultar útil señalar mediante comentarios el principio y el fin de bloques grandes o muy importantes dentro de la estructura del programa.
    Por ejemplo el siquiente caso:

    if (bInsertar)
      {  // ********* Inicio de insercción de datos ****************************
        ...
        ...
        // Aquí iría el código del bloque de insercción de datos
        // un montón de líneas, con bloques internos, etc...
        ...
        ...
      }  // ********* Fin de insercción de datos ******************************

[subir]

2.4 Paréntesis

  • Hay que hacer uso de los paréntesis para hacer más claro el orden de evaluación de operadores en una expresión, incluso en situaciones en las que puede no ser obligatorio utilizarlos

    Por ejemplo, la siguiente expresión, sin paréntesis, es correcta, pero poco legible:

    int i = a>=b && c<d && e+f <= g+h; // ¿Cual es el orden de evaluacion?

    De la siguiente manera es igual de correcta, pero más comprensible:

    int j = (a>=b) && (c<d) && ( (e+f) <= (g+h) ); // Expresion clara

  • Pese a todo, hay que tener cuidado y limitarse en el uso de los paréntesis, que pueden complicar la lectura del código.
    Si se tienen más de dos niveles de paréntesis en una sola extresión habría que dividirla en varias expresiones más sencillas (con cuatro niveles de paréntesis la lectura ya es sumamente complicada).
    De esta menera conseguimos un código resultante que puede ser igual de compacto, y resultará mucho más legible.

    Por ejemplo, en vez de usar:

    // demasiados paréntesis que hacen ilegible el código
    if (((4+(i*6))==x) && ((((x/5)-j)>=y) || ((6*x) != k))) hazAlgo();

    Es más legible utilizar lo siguiente:

    bool test1 = (4+(i*6) == x);
    bool test2 = ((x/5)-j >= y);
    bool test3 = (6*x != k);
    // conseguimos una condición más comprensible
    if (test1 && (test2 || test3)) hazAlgo();

[subir]

2.5 Espacios en blanco

  • Debe hacerse un uso generoso de líneas y espacios en blanco en pro de hacer más claro y comprensible el código.
    Las funciones y los bloques de código deben aislarse unos de otros, usando varias líneas en blanco para facilitar su lectura y poner de manifiesto su caracter de unidad de programación.

    Así conseguiremos tener un código de facil lectura (si fuera excesivamente compacto sería poco legible), y en el que sea sencillo localizar funciones y bloques de código.

  • Se pueden utilizar espacios en blanco para alinear la parte interna de sentencias o estrucutras, para así facilitar su lectura.

    Por ejemplo, en el siguiente código se han "colocado" partes de código para facilitar su lectura utilizando espacios en blanco:

    int   nContador = 0;
    int   vVar      = 0
    char* psAux     = NULL;
    ...
    ...
    incrementaVariable (nContador,  2);
    incrementaVariable (nVar,      32);
    ...

[subir]

2.6 Comentarios

  • Los comentarios deben ser minimizados (utilizar comentarios muy largos puede entorpecer la lectura), deben facilitar la comprensión del código y aportar información útil sobre las sentencias, bloques, variables, funciones, etc... que afectan.
    En ningún momento hay que poner demasiados comentarios (comentar todas las instrucciones utilizadas, por ejemplo, no aporta nada y entorpecen la lectura) que puedan dificultar la comprensión del programa o que no aporten ninguna información util sobre el mismo.

  • Es aconsejable comentar los ficheros, funciones y bloques de código, para así ofrecer información útil sobre su funcionalidad o su uso, pero sin extenderse de forma innecesaria.
    En otros apartados se comenta esto mismo, indicando la estructura de estos comentarios explicativos.

  • Se recomienda comentar las declaraciones de datos no autoexplicativas, y la omisión intencionada de código.

  • Hay mantener y actualizar los comentarios a la vez que se mantiene y actualiza el código.
    Unos comentarios no actualizados pueden llevar a error al revisar el fuente.

  • En C los comentarios solamente se construyen con /* ...... */.

    /* Estilo de comentario en C */
     
    /* Comentario que se escribiria en C
     * dividido en varias lineas. */

    En C hay que tener mucho cuidado al utilizar los comentarios que abarquen varias líneas.
    Algunos editores marcan con /* la primera linea del comentario y con * las siguientes, la última terminaría en */ (como en el ejemplo mostrado).

  • En C++ los comentarios tendrían que ser solamente los construidos con //.

    // Estilo de comentario en C++
     
    // Comentario que se escribiria en C++
    // dividido en varias lineas.

  • En caso de trabajar en C++ se aconseja utilizar sólamente los comentarios propios del C++. Los comentarios de C pueden llevar a errores ocultos en caso de tener comentarios anidados (que en unos compiladores producirían errores, y en otros no).

    El siguiente ejemplo de comentario puede no compilar en aslgunos compiladores

    /* Una primera linea de error
       /* Un comentario anidado */
       El comentario anidado puede provocar que no se compile.
       en determinados compiladores */

[subir]

2.7 Código

  • Nunca hay que poner rutas absolutas en el código. Ya que con ello conseguimos que el ejecutable dependa de la ruta absoluta indicada en la compilación, y tanto el código fuente como el ejecutable serían no portables.
    Si se necesita accedera a ficheros, directorios, etc... hay que usar otros metodos para llegar a ellos, como agumentos, variables de entorno, ficheros de configuración, etc...

  • Si fuera necesaria la portabilidad del código entre diferentes plataformas, se separarán las líneas propias de cada plataforma mediante sentencias de precompilación
    #if defined() ... #else ... #endif
    (usando defines que estarán bien documentados en la cabecera del fichero).

    Por ejemplo el siguiente caso:

    // Para windows se definirará WIN32 en la compilación
    #if defined (WIN32)
      struct _stat stbuf;
      resultado = _stat (path_evaluar, &stbuf);
    #else
      struct stat stbuf;
      resultado = stat (path_evaluar, &stbuf);
    #endif

[subir]

2.8 Compilación

  • Se aconseja compilar usando el nivel máximo de warnings disponible en el compilador y eliminar todos los avisos que aparezcan.
    Generalmente estos warnings hacen referencia a líneas de código problemáticas que es conveniente (aunque no sea imprescindible) solucionar.

  • Como se ha comentado en un punto anterior, hay que utilizar defines de precompilación para separar el código dependiente de cada plataforma cuando se busque la portabilidad de los ficheros fuente.

  • En la cabecera del fichero fuente hay que indicar los defines de precompilación que pueden utilizar y el motivo para utilizarlos.

    Conviene no abusar de los defines y sentencias de precompilación, ya que añaden complejidad al código.

[subir]


[< anterior]       [indice]       [siguiente >] Oscar Valtueña García - "Manual de estilo C / C++"