Quelles sont les conventions de dénomination les plus courantes en C?

126

Quelles sont les conventions de dénomination couramment utilisées en C? Je sais qu'il y en a au moins deux:

  1. GNU / linux / K&R avec des fonctions de cas_inférieures
  2. ? Nom ? avec les fonctions UpperCaseFoo

Je ne parle de C qu'ici. La plupart de nos projets sont de petits systèmes embarqués dans lesquels nous utilisons C.

Voici celui que je prévois d'utiliser pour mon prochain projet:


Convention de dénomination 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
la source
7
Je ne forcerais pas un préfixe «g_» sur les variables globales; J'imposerais des noms significatifs (donc client_locale et non cl_lc comme nom de variable globale). Classic C n'utilise pas de camel-case; J'ai écrit du code en camel-case en C, et ça a l'air bizarre (donc je ne le fais plus comme ça). Cela dit, ce n'est pas faux - et la cohérence est plus importante que la convention utilisée. Évitez les typedefs qui encapsulent des pointeurs de structure; considérez le standard C - «FILE *» est orthographié ainsi, pas FILE_PTR.
Jonathan Leffler
2
@Jonathan Leffler, quel est le problème avec g_ pour signifier les globaux? Dans les systèmes embarqués, j'ai déjà eu des problèmes dans lesquels il était difficile de retrouver les dépendances inter-modules via des variables globales et extern g_somevar. Personnellement, je pense que c'est généralement une mauvaise idée, mais ce genre de chose est généralement fait pour des raisons de performance. Par exemple, un indicateur global défini par une interruption indiquant que les données sont prêtes.
JeffV
2
Pour ce que ça vaut, cette convention de dénomination a été principalement extraite des conventions de l'API PalmOS. En outre, il est similaire à la convention utilisée dans le livre d'O'Reilly: "Programmer des systèmes embarqués avec des outils de développement C et GNU". Personnellement, j'aime le TitleCase dans les noms de fonctions. Je pensais aller avec lowerCamelCase dans les fonctions de liaison interne (que j'ai appelées privées dans ma question).
JeffV
3
@Chris Lutz, je suis d'accord, de tout cœur. Dans la mesure du possible, les var doivent être conservées dans la limite la plus étroite. Notez qu'il y a en fait trois portées dont nous discutons: local à une fonction, local à un module (pas de lien externe à la variable) et les globaux avec lien externe. Il est courant d'avoir des variables «globales à un module» dans les systèmes embarqués. Par conséquent, il faut prendre soin d'identifier les globaux avec un lien externe afin qu'ils puissent être réduits au minimum et les interactions du module comprises. C'est là que le préfixe "g_" est utile.
JeffV
46
J'aime préfixer les variables globales avec //.
plafer

Réponses:

129

La chose la plus importante ici est la cohérence. Cela dit, je suis la convention de codage GTK +, qui peut être résumée comme suit:

  1. Toutes les macros et constantes en majuscules: MAX_BUFFER_SIZE, TRACKING_ID_PREFIX.
  2. Noms de structure et typedef dans camelcase: GtkWidget, TrackingOrder.
  3. Fonctions qui opèrent sur les structures: style C classique: gtk_widget_show(), tracking_order_process().
  4. Pointeurs: rien d'extraordinaire ici: GtkWidget *foo, TrackingOrder *bar.
  5. Variables globales: n'utilisez simplement pas de variables globales. Ils sont mauvais.
  6. Des fonctions qui sont là, mais qui ne devraient pas être appelées directement, ou qui ont des utilisations obscures, ou autre: un ou plusieurs traits de soulignement au début: _refrobnicate_data_tables(), _destroy_cache().
axel_c
la source
13
Au point six, je préfère utiliser staticet ignorer le préfixe de module, donc si gtk_widget_show()c'était une fonction avec une portée de fichier, elle deviendrait simplement widget_show()avec une classe de stockage statique ajoutée.
Août Karlstrom
27
Note supplémentaire sur le point 6: le standard C a quelques règles sur la réservation de noms qui commencent par _pour l'implémentation et une utilisation future. Il y a quelques exceptions aux noms commençant par _mais à mon avis, cela ne vaut pas la peine de le mémoriser. Une règle sûre à suivre est de ne jamais utiliser de noms commençant par _dans votre code. Entrée de la FAQ C pertinente: c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=decl#namespace
jw013
5
Le n ° 2 est plus spécifiquement le cas supérieur de chameau ou le cas pascal . La casse camel ou la minuscule camel utilise des minuscules sur la première lettre.
Clint Pachl
9
Qu'en est-il des variables locales à plusieurs mots? my_var ou myVar?
Dean Gurvitz
4
Global variables: just don't use global variables. They are evil.- à moins que vous ne travailliez sur un projet intégré et que vous ayez 1024 octets de RAM et 8 MHz de processeur.
Kamil
30

Les "pointeurs de structure" ne sont pas des entités qui nécessitent une clause de convention de dénomination pour les couvrir. Ils sont juste struct WhatEver *. NE cachez PAS le fait qu'un pointeur est impliqué dans un typedef intelligent et "évident". Il ne sert à rien, est plus long à taper et détruit l'équilibre entre la déclaration et l'accès.

se détendre
la source
29
+1 pour le truc "ne pas cacher les pointeurs" - même si cette réponse ne répond pas (encore) à une grande partie du reste de la question.
Jonathan Leffler
1
@unwind, j'ai tendance à être d'accord. Cependant, parfois, un pointeur n'est pas destiné à être déréférencé externe et il s'agit davantage d'un handle vers le consommateur que d'un pointeur réel vers une structure qu'ils utiliseront. C'est pour cela que j'ai laissé le TitleCasePtr. typedef struct {champs} MyStruct, * MyStructPtr;
JeffV
Je supprime le TitleCasePtr, il distrait de la question réelle.
JeffV
1
-1 de ma part car une déclaration de type pointeur réduit l'encombrement, en particulier dans les signatures de fonction et le "déséquilibre" entre la déclaration et l'accès n'apparaît que dans le fichier d'implémentation - le client ne (ne devrait pas) accéder directement aux membres du champ.
Août Karlstrom
1
@AugustKarlstrom Très bien. Je ne comprends pas ce qui est "seulement" dans le fichier d'implémentation, n'est-ce pas aussi ce code? Je n'ai pas interprété la question comme portant uniquement sur les noms "externes". Tout le code est «implémentation» à un certain niveau.
détendre
17

Eh bien, premièrement, C n'a pas de fonctions publiques / privées / virtuelles. C'est du C ++ et il a des conventions différentes. En C, vous avez généralement:

  • Constantes dans ALL_CAPS
  • Des soulignements pour délimiter des mots dans des structures ou des noms de fonctions, vous ne voyez presque jamais la casse de chameau en C;
  • structs, typedefs, unions, members (of unions and structs) et enum values ​​sont généralement en minuscules (d'après mon expérience) plutôt que la convention C ++ / Java / C # / etc de faire de la première lettre une majuscule mais je suppose que c'est possible dans C aussi.

Le C ++ est plus complexe. J'ai vu un vrai mélange ici. Cas de chameau pour les noms de classe ou minuscules + traits de soulignement (le cas de chameau est plus courant dans mon expérience). Les structures sont rarement utilisées (et généralement parce qu'une bibliothèque les nécessite, sinon vous utiliseriez des classes).

cletus
la source
@cletus, je m'en rends compte. Par privé, j'entends des fonctions qui ne sont pas exposées en externe dans l'en-tête du module et qui ne sont pas destinées à être utilisées par du code externe au module. Public serait les fonctions de l'API du module destinées à être utilisées en externe.
JeffV
3
Vous pourriez considérer les fonctions statiques comme privées; la question ne mentionne pas virtuel. Mais +1 pour «voir rarement camel-case en C».
Jonathan Leffler
2
Je pense que Jeff parlait external linkagede «fonctions publiques» et internal linkagede «fonctions privées».
pmg
1
J'ai vu des constantes commençant par ak ainsi que dans: kBufferSize. Je ne sais pas d'où ça vient.
JeffV
2
ALL_CAPSest également souvent utilisé pour les valeurs d'énumération.
caf
15

Vous savez, j'aime garder les choses simples, mais claires ... Alors voici ce que j'utilise, en C:

  • Triviales variables : i,n,c(. Une seule lettre Si une lettre est pas claire, puis en faire une variable locale), etc ...
  • Variables locales :lowerCamelCase
  • Variables globales :g_lowerCamelCase
  • Variables const :ALL_CAPS
  • Variables du pointeur : ajoutez un p_au préfixe. Pour les variables globales, ce serait gp_var, pour les variables locales, pour les variables p_varconst p_VAR. Si des pointeurs éloignés sont utilisés, utilisez un fp_au lieu de p_.
  • Structs : ModuleCamelCase(Module = nom complet du module, ou une abréviation de 2-3 lettres, mais toujours en CamelCase.)
  • Variables des membres de structure :lowerCamelCase
  • Enums :ModuleCamelCase
  • Valeurs énumérées :ALL_CAPS
  • Fonctions publiques :ModuleCamelCase
  • Fonctions privées :CamelCase
  • Macros :CamelCase

J'ai tapé mes structures, mais j'utilise le même nom pour la balise et le typedef. La balise n'est pas destinée à être couramment utilisée. Au lieu de cela, il est préférable d'utiliser le typedef. Je transmets également déclarer le typedef dans l'en-tête du module public pour l'encapsulation et afin que je puisse utiliser le nom typedef'd dans la définition.

struct Exemple complet :

typdef struct TheName TheName;
struct TheName{
    int var;
    TheName *p_link;
};
SeanRamey
la source
Je ne sais rien du framework qt, mais vous pouvez écrire votre code dans le format de style que vous souhaitez. Rien ne vous en empêche, pour autant que je sache.
SeanRamey
10

Codant en C #, java, C, C ++ et objectif C en même temps, j'ai adopté une convention de dénomination très simple et claire pour me simplifier la vie.

Tout d'abord, il s'appuie sur la puissance des IDE modernes (comme eclipse, Xcode ...), avec la possibilité d'obtenir rapidement des informations en survolant ou en cliquant sur Ctrl ... En acceptant cela, j'ai supprimé l'utilisation de tout préfixe, suffixe et d'autres marqueurs qui sont simplement donnés par l'EDI.

Ensuite, la convention:

  • Tous les noms DOIVENT être une phrase lisible expliquant ce que vous avez. Comme "ceci est ma convention".
  • Ensuite, 4 méthodes pour obtenir une convention à partir d'une phrase:
    1. THIS_IS_MY_CONVENTION pour les macros, énumérer les membres
    2. ThisIsMyConvention pour nom de fichier, nom d'objet (classe, struct, enum, union ...), nom de fonction, nom de méthode, typedef
    3. this_is_my_convention variables globales et locales,
      paramètres, éléments struct et union
    4. thisismyconvention [facultatif] variables très locales et temporaires (comme un index de boucle for ())

Et c'est tout.

Il donne

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
la source
8

Je recommanderais de ne pas mélanger le cas de chameau et la séparation de soulignement (comme vous l'avez proposé pour les membres de struct). Ceci est déroutant. Vous penseriez, hey j'ai get_lengthdonc j'aurais probablement dû make_subsetet alors vous découvrirez que c'est en fait makeSubset. Utilisez le principe du moindre étonnement et soyez cohérent.

Je trouve CamelCase utile pour taper des noms, comme des structures, des typedefs et des énumérations. C'est à peu près tout, cependant. Pour tout le reste (noms de fonctions, noms de membres de struct, etc.) j'utilise underscore_separation.

Eli Bendersky
la source
1
Oui, le principal élément de toute convention de dénomination est la prévisibilité et la cohérence. De plus, comme la bibliothèque C elle-même utilise toutes les minuscules avec _ pour l'espacement, je recommanderais de l'utiliser pour ne pas avoir à gérer 2 conventions de dénomination différentes dans un projet (en supposant que vous n'écrivez pas un wrapper autour de la libc pour créer il est conforme à votre nom ... mais c'est grossier)
Earlz
Il utilise également des typedefs avec un " t" à la fin, mais je ne vois personne le recommander. En fait, la bibliothèque standard est même incohérente: div_t (stdlib.h) est une structure et tm aussi (time.h). Jetez également un œil aux membres de la structure tm, ils sont tous préfixés par tm, ce qui semble inutile et laid (IMO).
JeffV
1
"Je trouve que CamelCase est utile pour taper des noms ..." Si vous le démarrez en majuscules, c'est en fait PascalCase.
Tagc
7

En voici un (apparemment) rare, que j'ai trouvé utile: le nom du module dans CamelCase, puis un trait de soulignement, puis le nom de la fonction ou de la portée du fichier dans CamelCase. Donc par exemple:

Bluetooth_Init()
CommsHub_Update()
Serial_TxBuffer[]
Steve Melnikoff
la source
2
Pas si inhabituel, mais très utile.
chux - Réintégrer Monica
3

Je suis confus par une chose: vous prévoyez de créer une nouvelle convention de dénomination pour un nouveau projet. En règle générale, vous devez avoir une convention de dénomination à l'échelle de l'entreprise ou de l'équipe. Si vous avez déjà des projets qui ont une forme de convention de dénomination, vous ne devez pas changer la convention pour un nouveau projet. Si la convention ci-dessus n'est que la codification de vos pratiques existantes, alors vous êtes en or. Plus elle diffère des normes de facto existantes, plus il sera difficile de gagner la part d’esprit dans la nouvelle norme.

La seule suggestion que j'ajouterais est que j'ai pris goût à _t à la fin des types dans le style de uint32_t et size_t. C'est très C-ish pour moi même si certains pourraient se plaindre que c'est juste un hongrois "inversé".

jmucchiello
la source
3
Eh bien, les conventions ici sont partout et incohérentes, c'est pourquoi je me propose d'en documenter une. Aussi, c'est pourquoi je demande. Pour voir quel est le consensus communautaire.
JeffV
Je comprends cette douleur. Mais il doit y avoir un sous-ensemble de vos conventions existantes qui est le plus populaire. Vous devriez commencer par là et non sur une page Web Internet aléatoire. Vous devriez également demander à vos autres développeurs ce qu'ils considèrent comme bon.
jmucchiello
7
Je crois que les noms de type se terminant par _t sont réservés par la norme POSIX.
caf
4
Les noms finissant par _t sont réservés. Voir gnu.org/software/libc/manual/html_node/Reserved-Names.html , "Les noms qui se terminent par '_t' sont réservés pour des noms de types supplémentaires."
Étienne
2

Vous devriez également penser à l' ordre des mots pour faciliter la complétion automatique du nom .

Une bonne pratique: nom de la bibliothèque + nom du module + action + sujet

Si une partie n'est pas pertinente, sautez-la, mais au moins un nom de module et une action doivent toujours être présentés.

Exemples:

  • nom de la fonction: os_task_set_prio, list_get_size,avg_get
  • définir (ici généralement pas de partie action ):OS_TASK_PRIO_MAX
Gábor Kiss-Vámosi
la source
0

Il pourrait y en avoir beaucoup, principalement les IDE dictent certaines tendances et les conventions C ++ poussent également. Pour C communément:

  • UNDERSCORED_UPPER_CASE (définitions de macro, constantes, membres d'énumération)
  • underscored_lower_case (variables, fonctions)
  • CamelCase (types personnalisés: structs, enums, unions)
  • uncappedCamelCase (style Java oppa)
  • UnderScored_CamelCase (variables, fonctions sous type d'espaces de noms)

La notation hongroise pour les globaux est correcte mais pas pour les types. Et même pour les noms triviaux, veuillez utiliser au moins deux caractères.

Renonsz
la source
-1

Je pense que ceux-ci peuvent aider pour les débutants: convention de nommage des variables en c

  1. Vous devez utiliser le caractère alphabétique (az, AZ), le chiffre (0-9) et le score inférieur (_). Il n'est pas permis d'utiliser un caractère spécial comme:%, $, #, @ etc. Ainsi, vous pouvez utiliser user_name comme variable mais ne pouvez pas utiliser user & name .
  2. Impossible d'utiliser un espace blanc entre les mots. Ainsi, vous pouvez utiliser user_name ou username ou username comme variable mais ne pouvez pas utiliser de nom d'utilisateur .
  3. Impossible de commencer à nommer avec un chiffre. Ainsi, vous pouvez utiliser user1 ou user2 comme variable mais ne pouvez pas utiliser 1user .
  4. C'est un langage sensible à la casse. Les majuscules et les minuscules sont significatives. Si vous utilisez une variable comme le nom d'utilisateur, vous ne pouvez pas utiliser USERNAME ou Username pour le père.
  5. Vous ne pouvez utiliser aucun mot-clé (char, int, if, for, while etc.) pour la déclaration de variable.
  6. La norme ANSI reconnaît une longueur de 31 caractères pour un nom de variable
Amranur Rahman
la source
Cet article vise clairement à discuter des conventions de dénomination , pas des restrictions . Ce que vous avez énuméré sont des choses que vous ne pouvez même pas faire car ce sont des erreurs de syntaxe.
Chase le