¿Cuáles son las convenciones de nomenclatura más comunes en C?

125

¿Cuáles son las convenciones de nomenclatura que se usan comúnmente en C? Sé que hay al menos dos:

  1. GNU / linux / K&R con menos_funciones_case
  2. ? nombre ? con funciones UpperCaseFoo

Estoy hablando de C solo aquí. La mayoría de nuestros proyectos son pequeños sistemas integrados en los que usamos C.

Aquí está el que estoy planeando usar para mi próximo proyecto:


Convención de nomenclatura C

Struct              TitleCase
Struct Members      lower_case or lowerCase

Enum                ETitleCase
Enum Members        ALL_CAPS or lowerCase

Public functions    pfx_TitleCase (pfx = two or three letter module prefix)
Private functions   TitleCase
Trivial variables   i,x,n,f etc...
Local variables     lower_case or lowerCase
Global variables    g_lowerCase or g_lower_case (searchable by g_ prefix)
JeffV
fuente
77
No forzaría un prefijo 'g_' en las variables globales; Aplicaría nombres significativos (por lo tanto, client_locale y no cl_lc como nombre de variable global). Classic C no usa camel-case; He escrito código en camel-case en C, y se ve raro (así que ya no lo hago así). Dicho esto, no está mal, y la coherencia es más importante que la convención utilizada. Evite los typedefs que encapsulan punteros de estructura; considere el estándar C: 'FILE *' se escribe así, no FILE_PTR.
Jonathan Leffler
2
@Jonathan Leffler, ¿qué tiene de malo g_ para significar globales? En los sistemas embebidos, he tenido problemas antes en los que era difícil rastrear las dependencias entre módulos a través de variables globales y g_somevar externo. Personalmente, creo que generalmente es una mala idea, pero este tipo de cosas generalmente se hacen por razones de rendimiento. Por ejemplo, un indicador global que se establece mediante una interrupción que indica que los datos están listos.
JeffV
2
Por lo que vale, esta convención de nomenclatura se eliminó principalmente de las convenciones API de PalmOS. Además, es similar a la convención utilizada en el libro de O'Reilly: "Programación de sistemas integrados con herramientas de desarrollo C y GNU". Personalmente, me gusta el TitleCase en los nombres de las funciones. Estaba pensando en ir con lowerCamelCase en funciones de enlace interno (que llamé privado en mi pregunta).
JeffV
3
@ Chris Lutz, estoy de acuerdo, de todo corazón. Siempre que sea posible, los vars se mantendrán en el ámbito más estrecho. Tenga en cuenta que en realidad hay tres ámbitos que estamos discutiendo: local a una función, local a un módulo (sin vinculación externa a la variable) y los globales con vinculación externa. Es común tener variables "globales a un módulo" en sistemas embebidos. Por lo tanto, se debe tener cuidado para identificar los globales con enlaces externos para que puedan mantenerse al mínimo y se entiendan las interacciones del módulo. Aquí es donde el prefijo "g_" es útil.
JeffV
46
Me gusta prefijar las variables globales con //.
jugador

Respuestas:

127

Lo más importante aquí es la consistencia. Dicho esto, sigo la convención de codificación GTK +, que se puede resumir de la siguiente manera:

  1. Todas las macros y constantes en los casquillos: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Estructurar nombres y typedef's en camelcase: GtkWidget, TrackingOrder.
  3. Funciones que operan en estructuras: estilo clásico C: gtk_widget_show(), tracking_order_process().
  4. Punteros: nada especial aquí: GtkWidget *foo, TrackingOrder *bar.
  5. Variables globales: simplemente no use variables globales. Son malvados
  6. Funciones que están allí, pero que no deben llamarse directamente, o que tienen usos oscuros, o lo que sea: uno o más subrayados al principio: _refrobnicate_data_tables(), _destroy_cache().
axel_c
fuente
13
En el punto seis, prefiero usar staticy omitir el prefijo del módulo, por lo que si gtk_widget_show()fuera una función con alcance de archivo, se convertiría simplemente widget_show()con la clase de almacenamiento estático agregado.
August Karlstrom
27
Nota adicional sobre el punto 6: el estándar C tiene algunas reglas sobre la reserva de nombres que comienzan con la _implementación y el uso futuro. Hay algunas excepciones a los nombres que comienzan con, _pero en mi opinión, no vale la pena memorizar. Una regla segura para seguir es nunca usar nombres que comiencen _en su código. Entrada relevante de preguntas frecuentes de C: c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013
55
# 2 es más específicamente la caja del camello superior o la caja pascal . La caja de camello o la caja de camello inferior usa minúscula en la primera letra.
Clint Pachl
9
¿Qué pasa con las variables locales de varias palabras? my_var o myVar?
Dean Gurvitz
44
Global variables: just don't use global variables. They are evil.- a menos que esté trabajando en un proyecto integrado y tenga 1024 bytes de RAM y una CPU de 8MHz.
Kamil
30

Los "punteros de estructura" no son entidades que necesitan una cláusula de convención de nomenclatura para cubrirlos. Son justos struct WhatEver *. NO oculte el hecho de que hay un puntero involucrado en un typedef inteligente y "obvio". No sirve para nada, es más largo de escribir y destruye el equilibrio entre declaración y acceso.

relajarse
fuente
29
+1 para las cosas de "no ocultar punteros", aunque esta respuesta no aborda gran parte del resto de la pregunta (todavía).
Jonathan Leffler
1
@wind, tiendo a estar de acuerdo. Sin embargo, a veces un puntero no está destinado a ser desreferenciado externamente y es más un identificador para el consumidor que un puntero real a una estructura que utilizará. Para eso dejé el TitleCasePtr. typedef struct {fields} MyStruct, * MyStructPtr;
JeffV
Estoy eliminando el TitleCasePtr, es una distracción de la pregunta real.
JeffV
1
-1 de mí ya que una declaración de tipo de puntero reduce el desorden, especialmente en las firmas de funciones y el "desequilibrio" entre la declaración y el acceso solo aparece en el archivo de implementación: el cliente no (no debería) acceder a los miembros del campo directamente.
August Karlstrom
1
@AugustKarlstrom Bien. Sin embargo, no entiendo qué es tan "solo" sobre el archivo de implementación, ¿no es ese código también? No interpreté la pregunta como si solo se tratara de nombres "externos". Todo el código es "implementación" en algún nivel.
Relájese el
17

Bueno, en primer lugar, C no tiene funciones públicas / privadas / virtuales. Eso es C ++ y tiene diferentes convenciones. En C normalmente tienes:

  • Constantes en ALL_CAPS
  • Subraya la delimitación de palabras en estructuras o nombres de funciones, casi nunca ve el caso de camello en C;
  • structs, typedefs, uniones, miembros (de uniones y estructuras) y los valores de enumeración suelen estar en minúsculas (en mi experiencia) en lugar de la convención C ++ / Java / C # / etc. de convertir la primera letra en mayúscula, pero supongo que es posible en C también.

C ++ es más complejo. He visto una verdadera mezcla aquí. Caso de camello para nombres de clase o minúsculas + guiones bajos (el caso de camello es más común en mi experiencia). Las estructuras se usan raramente (y típicamente porque una biblioteca las requiere, de lo contrario usaría clases).

cletus
fuente
@cletus, me doy cuenta de eso. Por privado quiero decir funciones que no están expuestas externamente en el encabezado del módulo y no están destinadas a ser utilizadas por código externo al módulo. Público serían funciones API de módulo destinadas a ser utilizadas externamente.
JeffV
3
Podría considerar las funciones estáticas como privadas; La pregunta no menciona virtual. Pero +1 para 'rara vez se ven casos de camellos en C'.
Jonathan Leffler
2
Creo que Jeff se refería external linkagea "funciones públicas" y internal linkagea "funciones privadas".
pmg
1
He visto constantes que comienzan con ak y también en: kBufferSize. No estoy seguro de dónde viene eso.
JeffV
2
ALL_CAPSa menudo también se usa para valores enum.
caf
14

Sabes, me gusta mantenerlo simple, pero claro ... Así que esto es lo que uso, en C:

  • Variables triviales :, i,n,cetc. (solo una letra. Si una letra no está clara, conviértala en una variable local)
  • Las variables locales :lowerCamelCase
  • Variables globales :g_lowerCamelCase
  • Variables Const :ALL_CAPS
  • Variables de puntero : agregue p_a al prefijo. Para variables globales sería gp_var, para variables locales p_var, para variables constantes p_VAR. Si se utilizan punteros lejanos, utilice un en fp_lugar de p_.
  • Estructuras : ModuleCamelCase(Módulo = nombre completo del módulo, o una abreviatura de 2-3 letras, pero aún en CamelCase.)
  • Variables de miembro de estructura :lowerCamelCase
  • Enumeraciones :ModuleCamelCase
  • Valores de enumeración :ALL_CAPS
  • Funciones publicas :ModuleCamelCase
  • Funciones privadas :CamelCase
  • Macros :CamelCase

Escribo typedef my structs, pero uso el mismo nombre para la etiqueta y typedef. La etiqueta no está destinada a ser de uso común. En cambio, es preferible usar typedef. También reenvío la declaración typedef en el encabezado del módulo público para la encapsulación y para poder usar el nombre typedef'd en la definición.

struct Ejemplo completo :

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};
SeanRamey
fuente
No sé nada sobre el marco qt, pero puede escribir su código en el formato de estilo que desee. Nada te impide, por lo que yo sé.
SeanRamey
10

Codificación en C #, java, C, C ++ y objetivo C al mismo tiempo, adopté una convención de nomenclatura muy simple y clara para simplificar mi vida.

En primer lugar, se basa en el poder de los IDE modernos (como eclipse, Xcode ...), con la posibilidad de obtener información rápida al pasar el mouse o presionar Ctrl ... Al aceptar eso, eliminé el uso de cualquier prefijo, sufijo y otros marcadores que simplemente proporciona el IDE.

Entonces, la convención:

  • Cualquier nombre DEBE ser una oración legible que explique lo que tienes. Como "esta es mi convención".
  • Luego, 4 métodos para sacar una convención de una oración:
    1. THIS_IS_MY_CONVENTION para macros, miembros de enumeración
    2. ThisIsMyConvention para nombre de archivo, nombre de objeto (clase, estructura, enumeración, unión ...), nombre de función, nombre de método, typedef
    3. this_is_my_convention variables globales y locales,
      parámetros, estructura y elementos de unión
    4. thisismyconvention [opcional] variables muy locales y temporales (como un índice de bucle for ())

Y eso es.

Da

class MyClass {
    enum TheEnumeration {
        FIRST_ELEMENT,
        SECOND_ELEMENT,
    }

    int class_variable;

    int MyMethod(int first_param, int second_parameter) {
        int local_variable;
        TheEnumeration local_enum;
        for(int myindex=0, myindex<class_variable, myindex++) {
             localEnum = FIRST_ELEMENT;
        }
    }
}
Luc Fourestier
fuente
8

Recomendaría no mezclar mayúsculas y minúsculas y subrayar la separación (como usted propuso para los miembros de la estructura). Esto es confuso. Podrías pensar, hey, tengo, get_lengthasí que probablemente debería haberlo hecho make_subsety luego descubres que en realidad es así makeSubset. Use el principio de mínimo asombro y sea consistente.

Encuentro que CamelCase es útil para escribir nombres, como estructuras, typedefs y enumeraciones. Eso es todo, sin embargo. Para todo lo demás (nombres de funciones, nombres de miembros de estructura, etc.) utilizo underscore_separation.

Eli Bendersky
fuente
1
Sí, lo principal de cualquier convención de nomenclatura es la previsibilidad y la coherencia. Además, debido a que la propia biblioteca C usa todas las minúsculas con _ para el espaciado, recomendaría usar eso solo para que no tenga que lidiar con 2 convenciones de nomenclatura diferentes en un proyecto (suponiendo que no escriba un contenedor alrededor de libc para hacer se ajusta a su nombre ... pero eso es asqueroso)
Earlz
También usa typedefs con una " t" al final, pero no veo a nadie que lo recomiende. De hecho, la biblioteca estándar es incluso inconsistente: div_t (stdlib.h) es una estructura y también lo es tm (time.h). Además, eche un vistazo a los miembros de tm struct, todos tienen el prefijo tm que parece inútil y feo (IMO).
JeffV
1
"Creo que CamelCase es útil para escribir nombres ..." Si comienzas con mayúsculas, en realidad es PascalCase.
Tagc
7

Aquí hay uno (aparentemente) poco común, que he encontrado útil: el nombre del módulo en CamelCase, luego un guión bajo, luego la función o el nombre del alcance del archivo en CamelCase. Así por ejemplo:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]
Steve Melnikoff
fuente
2
No tan inusual, pero muy útil.
chux - Restablecer Monica
3

Estoy confundido por una cosa: estás planeando crear una nueva convención de nomenclatura para un nuevo proyecto. En general, debe tener una convención de nomenclatura que abarque toda la empresa o el equipo. Si ya tiene proyectos que tienen alguna forma de convención de nomenclatura, no debe cambiar la convención para un nuevo proyecto. Si la convención anterior es solo la codificación de sus prácticas existentes, entonces usted es dorado. Cuanto más se diferencie de los estándares de facto existentes, más difícil será ganar mente en el nuevo estándar.

La única sugerencia que agregaría es que me ha gustado _t al final de los tipos en el estilo de uint32_t y size_t. Para mí es muy c-ish, aunque algunos podrían quejarse de que es simplemente "húngaro" inverso.

jmucchiello
fuente
3
Bueno, las convenciones aquí están por todas partes y son inconsistentes, por eso me propongo documentar una. Además, es por eso que estoy preguntando. Para ver cuál es el consenso de la comunidad.
JeffV
Entiendo ese dolor. Pero debe haber algún subconjunto de sus convenciones existentes que sea más popular. Debe comenzar allí y no en una página web aleatoria de Internet. También debes preguntar a tus otros desarrolladores qué considerarían bueno.
jmucchiello
77
Creo que los nombres de tipo que terminan en _t están reservados por el estándar POSIX.
caf
44
Los nombres que terminan con _t están reservados. Consulte gnu.org/software/libc/manual/html_node/Reserved-Names.html , "Los nombres que terminan con '_t' están reservados para nombres de tipo adicionales".
Étienne
2

También debe pensar en el orden de las palabras para completar el nombre automático .

Una buena práctica: nombre de biblioteca + nombre de módulo + acción + tema

Si una parte no es relevante, simplemente omítala, pero siempre se debe presentar al menos un nombre de módulo y una acción.

Ejemplos:

  • nombre de la función: os_task_set_prio, list_get_size,avg_get
  • define (aquí generalmente no hay parte de acción ):OS_TASK_PRIO_MAX
Gábor Kiss-Vámosi
fuente
0

Podría haber muchos, principalmente IDE dictan algunas tendencias y las convenciones de C ++ también están presionando. Para C comúnmente:

  • UNDERSCORED_UPPER_CASE (definiciones de macro, constantes, miembros de enumeración)
  • underscored_lower_case (variables, funciones)
  • CamelCase (tipos personalizados: estructuras, enumeraciones, uniones)
  • uncappedCamelCase (estilo Java oppa)
  • UnderScored_CamelCase (variables, funciones bajo tipo de espacios de nombres)

La notación húngara para los globales está bien pero no para los tipos. E incluso para nombres triviales, utilice al menos dos caracteres.

renonsz
fuente
-1

Creo que pueden ayudar para principiantes: convención de nomenclatura de variables en c

  1. Debe usar el carácter alfabético (az, AZ), el dígito (0-9) y la puntuación inferior (_). No está permitido usar ningún Carácter especial como:%, $, #, @ etc. Por lo tanto, puede usar user_name como variable pero no puede usar user & name .
  2. No puede usar espacios en blanco entre palabras. Por lo tanto, puede usar user_name o username o username como variable pero no puede usar el nombre de usuario .
  3. No se puede comenzar a nombrar con dígitos. Por lo tanto, puede usar user1 o user2 como variable pero no puede usar 1user .
  4. Es un lenguaje sensible a mayúsculas y minúsculas. Mayúsculas y minúsculas son significativas. Si usa una variable como nombre de usuario, entonces no puede usar USERNAME o Username para uso de padre.
  5. No puede usar ninguna palabra clave (char, int, if, for, while, etc.) para la declaración de variables.
  6. El estándar ANSI reconoce una longitud de 31 caracteres para un nombre de variable
Amranur Rahman
fuente
Esta publicación claramente pretende discutir convenciones de nomenclatura , no restricciones . Lo que enumeró son cosas que ni siquiera puede hacer porque son errores de sintaxis.
Chase