Convenciones de nomenclatura utilizadas para variables y funciones en C [cerrado]

13

Mientras que la codificación de un gran proyecto en CI se encontró con un problema. Si sigo escribiendo más código, habrá un momento en que me será difícil organizar el código. Quiero decir que la denominación de funciones y variables para diferentes partes del programa puede parecer confusa.

¿Estaba pensando si hay convenciones de nomenclatura útiles que pueda usar para las variables y funciones de C?

La mayoría de los idiomas sugieren una convención de nomenclatura. Pero para C, lo único que he leído hasta ahora es que los nombres deben ser descriptivos para la legibilidad del código.

EDITAR:

Ejemplos de algunos ejemplos de convenciones de nomenclatura sugeridas:

Leí algunas convenciones de nombres más para Java en alguna parte, pero no podía recordar dónde.

Aseem Bansal
fuente
Cite algunos ejemplos de idiomas con convenciones de nomenclatura sugeridas. Y donde podemos encontrar esas convenciones de nombres.
Philip
@Philip Ejemplos agregados
Aseem Bansal
1
No debería haber un problema con las variables, ya que no usa globales. Y para los nombres de funciones: si el nombre del módulo es order.c, podría nombrar las funciones order_add(), order_del()y tal. Puede haber sistemas antiguos que le indiquen que el nombre debe ser único dentro de los primeros 8 caracteres. Cuando cambies a c ++ más tarde por accidente, te encantará escribir order::add()y order::del()luego.
ott--

Respuestas:

17

Si sigo escribiendo más código, habrá un momento en que me será difícil organizar el código.

Este es su problema: haga que la organización sea correcta y el estilo debería fluir más fácilmente.

No espere para organizar su código: mantenga su código organizado a medida que avanza. Aunque el lenguaje no lo hace por usted, el código aún debe organizarse en módulos con bajo acoplamiento y alta cohesión.

Estos módulos proporcionan naturalmente un espacio de nombres. Abrevie el nombre del módulo (si es largo) y prefije los nombres de las funciones con su módulo para evitar colisiones.

A nivel de identificadores individuales, estos están más o menos en orden creciente de subjetividad:

  1. elige una convención y síguela
    • por ejemplo, function_like_this(struct TypeLikeThis variable)es común
  2. definitivamente evite la notación húngara (lo siento JNL)

    • a menos que esté dispuesto a usarlo como se pretendía originalmente, lo que significa la notación de aplicaciones de Simonyi en lugar de la terrible versión del sistema

      ¿Por qué? Podría escribir un ensayo sobre esto, pero en su lugar te sugiero que leas este artículo de Joel Spolsky, y luego busques un poco más si estás interesado. Hay un enlace al artículo original de Simonyi en la parte inferior.

  3. evite los tipos de puntero a menos que sean tipos de cookies genuinamente opacos; solo confunden cosas

    struct Type *ok;
    typedef struct Type *TypePtr;
    TypePtr yuck;
    

    ¿Qué quiero decir con un tipo de cookie opaco ? Me refiero a algo usado dentro de un módulo (o biblioteca, o lo que sea) que debe pasarse al código del cliente, pero ese código del cliente no puede usarse directamente. Simplemente lo devuelve a la biblioteca.

    Por ejemplo, una biblioteca de base de datos podría exponer una interfaz como

    /* Lots of buffering, IPC and metadata magic held in here.
       No, you don't get to look inside. */
    struct DBContextT;
    /* In fact, you only ever get a pointer, so let's give it a nice name */
    typedef struct DBContexT *DBContext;
    
    DBContext db_allocate_context(/*maybe some optional flags?*/);
    void db_release_context(DBContext);
    int db_connect(DBContext, const char *connect);
    int db_disconnect(DBContext);
    int db_execute(DBContext, const char *sql);
    

    Ahora, el contexto es opaco al código del cliente, porque no puede mirar dentro. Simplemente devuélvelo a la biblioteca. Algo así FILEtambién es opaco, y un descriptor de archivo entero también es una cookie , pero no es opaco.


Una nota sobre diseño

Utilicé la frase bajo acoplamiento y alta cohesión arriba sin explicación, y me siento un poco mal por eso. Puede buscarlo y probablemente encuentre algunos buenos resultados, pero intentaré abordarlo brevemente (nuevamente, podría escribir un ensayo pero intentaré no hacerlo).

La biblioteca de DB esbozada anteriormente muestra un bajo acoplamiento porque expone una pequeña interfaz al mundo exterior. Al ocultar sus detalles de implementación (en parte con el truco de las cookies opacas), evita que el código del cliente dependa de esos detalles.

Imagine en lugar de la cookie opaca, declaramos la estructura de contexto para que su contenido sea visible, y eso incluye un descriptor de archivo de socket para una conexión TCP a la base de datos. Si posteriormente cambiamos la implementación para admitir el uso de un segmento de memoria compartida cuando la base de datos se ejecuta en la misma máquina, el cliente debe volver a compilarse en lugar de volver a vincularse. Peor aún, el cliente podría haber comenzado a usar el descriptor de archivo, por ejemplo, llamando setsockoptpara cambiar el tamaño predeterminado del búfer, y ahora también necesita un cambio de código. Todos estos detalles deben ocultarse dentro de nuestro módulo cuando sea práctico, y esto proporciona un bajo acoplamiento entre módulos.

El ejemplo también muestra una alta cohesión , ya que todos los métodos en el módulo están relacionados con la misma tarea (acceso a la base de datos). Esto significa que solo el código que necesita conocer los detalles de implementación (es decir, el contenido de nuestra cookie) realmente tiene acceso a ellos, lo que simplifica la depuración.

También puede ver que tener una sola preocupación facilitaba la elección de un prefijo para agrupar estas funciones.

Ahora, decir que este ejemplo es bueno es fácil (especialmente porque ni siquiera está completo), pero no lo ayuda de inmediato. El truco es observar, a medida que escribe y extiende su código, las funciones que hacen cosas similares u operan en los mismos tipos (que podrían ser candidatos para su propio módulo), y también las funciones que hacen muchas cosas separadas que no son No está realmente relacionado y podría ser candidato para separarse.

Inútil
fuente
¿Me pueden ayudar a entender por qué se evita el húngaro? Solo curiosidad por saber más al respecto. :)
JNL
@JNL: Un comentario es demasiado corto para explicarlo adecuadamente. Te sugiero que lo publiques como una nueva pregunta.
Bart van Ingen Schenau
with low coupling and high cohesion. Qué significa eso? Y explique sobre los tipos de cookies opacos. No tengo idea de lo que eso significa.
Aseem Bansal
Traté de abordar ambos brevemente, y francamente fallé en brevedad. Sin embargo, espero que te ayude a comenzar.
Inútil
Estoy respondiendo después de unos días. Lo siento por eso. Leí tu descripción de low coupling and high cohesion. Por lo tanto, básicamente significa encapsular cosas cuando puedo y debe hacerse de una manera que las funciones que realmente necesitan deberían tener acceso. Algunas cosas pasaron por mi cabeza, pero aún creo que entendí tu punto.
Aseem Bansal
5

En mi opinión, el 90% del problema de nomenclatura se resuelve si tiene en cuenta tres cosas: a) haga que sus nombres de variables y funciones sean lo más descriptivos posible, b) sea ​​coherente en todo su código (es decir, si una función se llama addNumbers, a la segunda función debe llamarse multiplyNumbers y no numbersMul) yc) intentar acortar los nombres si es posible, ya que necesitamos escribirlos.

Dicho esto, si desea echar un vistazo a otros aspectos sobre este tema, la página de Wikipedia sobre Convenciones de nomenclatura tiene una buena lista de cosas que debe tener en cuenta. También tiene una sección en C y C ++:

En C y C ++, las palabras clave y los identificadores de biblioteca estándar están en minúsculas. En la biblioteca estándar de C, los nombres abreviados son los más comunes (por ejemplo, isalnum para una función que prueba si un carácter es alfanumérico), mientras que la biblioteca estándar de C ++ a menudo usa un guión bajo como separador de palabras (por ejemplo, out_of_range). Los identificadores que representan macros se escriben, por convención, usando solo letras mayúsculas y guiones bajos (esto está relacionado con la convención en muchos lenguajes de programación de usar identificadores en mayúsculas para constantes). Los nombres que contienen un guión bajo doble o que comienzan con un guión bajo y una letra mayúscula están reservados para la implementación (compilador, biblioteca estándar) y no deben usarse (por ejemplo, reservados__ o _Reservados). [5] [6] Esto es superficialmente similar al stripping, pero la semántica difiere:

Daniel Scocco
fuente
3
"intente acortar los nombres si es posible" Use un IDE con autocompletado, luego los nombres de sus funciones pueden ser tan largos y descriptivos como sea necesario, ya que solo necesita escribirlos una vez.
Joel
1
@ Joel consejos terribles. No todos usarán el mismo IDE que usted.
James
66
@ James No necesitan hacerlo, simplemente pueden usar cualquier IDE decente. Entonces no tiene que sacrificar la claridad por la productividad.
Joel
El término IDE se alarga un poco hoy en día. Técnicamente, Notepad ++ es un IDE porque puede configurarlo para compilar y ejecutar su proyecto, pero es principalmente un editor de texto. Y se completa automáticamente.
Philip
5

La única restricción difícil en C es que no hay espacios de nombres. Por lo tanto, debe encontrar una manera de diferenciar la función de la biblioteca rename()de su sistema de archivos de la rename()función de su biblioteca de medios . La solución habitual es un prefijo, como: filesystem_rename()y media_rename().

El otro consejo general es: mantenerse constante dentro de un proyecto o un equipo. Se mejorará la legibilidad.

Mouviciel
fuente
+1: Eso es especialmente cierto para los símbolos exportados en una biblioteca. "Lo siento, pero esa biblioteca de sistema de archivos no va con esa biblioteca de medios, porque ambos tienen un nombre de función exportado.
Residuo
2

SI BUSCA UN FORMATO GLOBALMENTE ACEPTADO

MISRA / JSF / AUTOSAR cubre casi el 100% de todos los estándares de la industria para nombrar y organizar código C / C ++. El problema es que no se conseguirán gratuitamente, es decir, cada una de las guías cuesta algo de dinero. Sé que el libro estándar de codificación MISRA 2008 C / C ++ probablemente cuesta alrededor de 50 USD.

Puede pensar en esto como la referencia de Harvard para bibliografía y lectura adicional cuando escribe un diario. He usado MISRA y es una buena forma de nombrar sus funciones y variables, y organizarlas para un uso adecuado.

SI BUSCAS ALGO TEMPORAL

Las referencias que proporcionó para Python y Java están bien, supongo. He visto a personas que adoptan el estilo javadoc comentando, nombrando y organizando el código. De hecho, en mi último proyecto, tuve que escribir código C ++ en funciones / nombres de variables similares a Java. Dos razones detrás de esto:

1) Aparentemente fue más fácil de seguir.

2) Los requisitos del código de producción no tocaron el terreno de los estándares de sistemas de software críticos para la seguridad.

3) El código heredado estaba (de alguna manera) en ese formato.

4) Doxygen permitió comentarios de Javadoc. En ese momento, estábamos usando doxygen para generar documentación para los chicos de producción.

Muchos programadores se opondrán a esto, pero personalmente creo que no hay nada de malo en adoptar la función de estilo javadoc / nomenclatura variable en C / C ++. SÍ POR SUPUESTO, las prácticas de organizar su control de flujo, seguridad de roscas, etc. deben abordarse independientemente. Sin embargo, no soy un solicitante aquí. Tampoco sé cuán estrictos son los requisitos de formato del código de producción. Sin desviarlo a un área fuera del tema, le sugiero que revise sus requisitos, descubra qué tan dependiente es de una convención de nomenclatura específica y elija una solución mencionada en las respuestas mías y de otros.

Espero que esto haya ayudado?

Hagubear
fuente
En realidad estaba pidiendo esto para los códigos personales C. Pero recordaré tu sugerencia.
Aseem Bansal
@AseemBansal Personal o profesional, son buenos para aprender y también para poner en tu CV :) .... Depende de ti.
hagubear
0

Pocas cosas importantes a tener en cuenta al nombrar serían;

  1. Considere el tipo actionObject u ObjectAction. (Objeto no para C. Pero en general cuando va a otros lenguajes orientados a objetos) Esto debería ayudar

  2. El descanso sería CONSISTENTE, breve y descriptivo seguro.

  3. Además, tenga un único propósito para cada variable y función definida, por ejemplo: si es para almacenar un valor temporalmente, asígnele el nombre nTempVal para int
  4. Las variables deben ser sustantivos y los métodos deben ser verbos.
JNL
fuente
66
La notación húngara (prefijando una variable con letras que denotan el tipo) conduce a un sinfín de dolores. Afortunadamente, ha pasado de moda.
Gort the Robot
@StevenBurnap ¿Tenía curiosidad por qué se evita el formato húngaro? Creo que eso es lo que nos enseñaron en la escuela y también he visto ese código en algunos lugares de trabajo. ¿Cuál recomendarías si no es húngaro? Gracias
JNL
1
La mejor convención de nomenclatura es la que se usa de manera sistemática, con nombres claros y descriptivos, idealmente relativamente cortos, sin abreviaciones excesivas y evitando prefijos redundantes. La notación húngara tiene poca utilidad real, hace que el código sea más difícil de leer y hace que cambiar los tipos sea más difícil.
Gort the Robot
2
Aquí hay una descripción de la intención original y la abominación en que se ha convertido la notación húngara: joelonsoftware.com/articles/Wrong.html
Residuo
@Residuum Ese fue un buen enlace. Ayudó mucho Lo aprecio.
JNL
0

La mayoría de las respuestas son buenas, pero quiero decir algunas cosas sobre las convenciones de nomenclatura para las bibliotecas y los archivos incluidos, de manera similar al uso de espacios de nombres en otros lenguajes como C ++ o Java:

Si crea una biblioteca, busque un prefijo común para sus símbolos exportados, es decir, funciones globales, typedefs y variables. Esto evitará enfrentamientos con otras bibliotecas e identificará las funciones que provienen de la suya. Este es un poco de notación húngara de aplicaciones.

Tal vez vaya más allá y agrupe sus símbolos exportados: libcurl usa curl_ * para símbolos globales, curl_easy_ *, curl_multi_ * y curl_share_ * para las diferentes interfaces. Por lo tanto, además de usar curl_ * para todas las funciones, han agregado otro nivel de "espacios de nombres" para las diferentes interfaces: llamar a una función curl_easy_ * en un controlador curl_multi_ * ahora parece incorrecto, vea los nombres de las funciones en http: // curl. haxx.se/libcurl/c/

Manteniendo las reglas para los símbolos exportados, debe usarlos para las funciones estáticas en los #includearchivos ed: intente encontrar un prefijo común para estas funciones. ¿Quizás tenga funciones de utilidad de cadena estática en un archivo llamado "my_string"? Prefije todas esas funciones con my_string_ *.

Residuo
fuente
Por símbolos exportados te refieres a variables globales, funciones, typedefs, etc. si estoy en lo correcto. ¿Puedes explicarnos un poco acerca de cómo agrupar los símbolos exportados? Pensé que ya lo habías explicado en el párrafo anterior. ¿Qué agregaste en el tercer párrafo?
Aseem Bansal