Lors du codage d'un grand projet en C, je suis tombé sur un problème. Si je continue à écrire plus de code, il y aura un moment où il sera difficile pour moi d'organiser le code. Je veux dire que la dénomination des fonctions et des variables pour différentes parties du programme peut sembler mélangée.
Je me demandais donc s'il existe des conventions de dénomination utiles que je peux utiliser pour les variables et les fonctions C?
La plupart des langues suggèrent une convention de dénomination. Mais pour C, la seule chose que j'ai lu jusqu'à présent est que les noms doivent être descriptifs pour la lisibilité du code.
ÉDITER:
Exemples de quelques exemples de conventions de dénomination suggérées:
J'ai lu quelques conventions de dénomination supplémentaires pour Java quelque part mais je ne me souviens plus où.
Si je continue à écrire plus de code, il y aura un moment où il sera difficile pour moi d'organiser le code.
C'est votre problème: obtenir la bonne organisation et le style devrait couler plus facilement.
Ne pas attends pour organiser ton code: garde ton code organisé au fur et à mesure. Bien que le langage ne le fasse pas pour vous, le code doit toujours être organisé en modules avec un faible couplage et une forte cohésion.
Ces modules fournissent alors naturellement un espace de noms. Abréger le nom du module (s'il est long) et préfixer les noms de fonction avec leur module pour éviter les collisions.
Au niveau des identifiants individuels, ceux-ci sont à peu près en ordre croissant de subjectivité:
function_like_this(struct TypeLikeThis variable)
est communéviter absolument la notation hongroise (désolé JNL)
sauf si vous êtes prêt à l'utiliser comme prévu à l'origine, ce qui signifie la notation - applications de Simonyi plutôt que la terrible version du système
Pourquoi? Je pourrais écrire un essai à ce sujet, mais je vous suggérerai plutôt de lire cet article par Joel Spolsky, puis de chasser un peu plus si vous êtes intéressé. Il y a un lien vers le papier original de Simonyi en bas.
éviter les pointeurs typedefs à moins qu'ils ne soient de véritables types de cookies opaques - ils ne font que confondre les choses
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
Qu'est-ce que je veux dire par un type de cookie opaque? Je veux dire quelque chose utilisé dans un module (ou une bibliothèque, ou autre) qui doit être transmis au code client, mais ce code client ne peut pas utiliser directement. Il le renvoie simplement à la bibliothèque.
Par exemple, une bibliothèque de base de données peut exposer une interface comme
/* 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);
Maintenant, le contexte est opaque au code client, car vous ne pouvez pas regarder à l'intérieur. Vous venez de le renvoyer à la bibliothèque. Quelque chose comme FILE
est également opaque, et un descripteur de fichier entier est également un cookie, mais n'est pas opaque.
J'ai utilisé l'expression faible couplage et grande cohésion ci-dessus sans explication, et je me sens un peu mal à ce sujet. Vous pouvez le rechercher et trouver probablement de bons résultats, mais je vais essayer d'y répondre brièvement (encore une fois, je pourrais écrire un essai mais j'essaierai de ne pas le faire).
La bibliothèque DB esquissée ci-dessus montre faible couplage car elle expose une petite interface au monde extérieur. En cachant ses détails d'implémentation (en partie avec l'astuce de cookie opaque), il empêche le code client de dépendre de ces détails.
Imaginez au lieu du cookie opaque, nous déclarons la structure de contexte de sorte que son contenu soit visible, et qui inclut un descripteur de fichier socket pour une connexion TCP à la base de données. Si nous modifions ensuite l'implémentation pour la prendre en charge en utilisant un segment de mémoire partagée lorsque la base de données s'exécute sur la même machine, le client doit être recompilé plutôt que simplement rétabli. Pire encore, le client aurait pu démarrer en utilisant le fichier descripteur, par exemple en appelant setsockopt
pour changer la taille de tampon par défaut, et maintenant il a également besoin d'un changement de code. Tous ces détails doivent être cachés à l'intérieur de notre module lorsque cela est possible, et cela donne un faible couplage entre modules.
L'exemple montre également haute cohésion, en ce sens que toutes les méthodes du module concernent la même tâche (accès DB). Cela signifie que seul le code dont a besoin pour connaître les détails de l'implémentation (c'est-à-dire le contenu de notre cookie) y a réellement accès, ce qui simplifie le débogage.
Vous pouvez également voir qu'avoir une seule préoccupation a facilité le choix d'un préfixe pour regrouper ces fonctions.
Maintenant, dire que cet exemple est bon est facile (d'autant plus qu'il n'est même pas complet), mais ne vous aide pas immédiatement. L'astuce consiste à surveiller, pendant que vous écrivez et étendez votre code, les fonctions qui font des choses similaires ou qui fonctionnent sur les mêmes types (qui pourraient être candidates à leur propre module), ainsi que les fonctions qui font beaucoup de choses distinctes qui ne sont pas '' t vraiment liés, et pourraient être candidats à la scission.
À mon avis, 90% du problème de dénomination est résolu si vous gardez trois choses à l'esprit: a) rendez vos noms de variables et de fonctions aussi descriptifs que possible, b) être cohérent dans tout votre code (c.-à-d., si une fonction est nommée addNumbers, une deuxième fonction doit être nommée multiplyNumbers et non numberMul) et c) essayez de raccourcir les noms si possible, car nous devons les saisir.
Cela étant dit, si vous voulez jeter un œil à d'autres aspects de ce sujet, la page Wikipedia sur Conventions de dénomination a une bonne liste de choses que vous devez garder à l'esprit. Il a également une section sur C et C++:
En C et C++, les mots clés et les identificateurs de bibliothèque standard sont pour la plupart en minuscules. Dans la bibliothèque standard C, les noms abrégés sont les plus courants (par exemple isalnum pour une fonction testant si un caractère est alphanumérique), tandis que la bibliothèque standard C++ utilise souvent un trait de soulignement comme séparateur de mots (par exemple out_of_range). Les identifiants représentant les macros sont, par convention, écrits en utilisant uniquement des lettres majuscules et des traits de soulignement (ceci est lié à la convention dans de nombreux langages de programmation d'utiliser des identifiants tout en majuscules pour les constantes). Les noms contenant un double trait de soulignement ou commençant par un trait de soulignement et une majuscule sont réservés à l'implémentation (compilateur, bibliothèque standard) et ne doivent pas être utilisés (par exemple réservé__ ou _Réservé). [5] [6] Ceci est superficiellement similaire au stropping, mais la sémantique diffère: les traits de soulignement font partie de la valeur de l'identifiant, plutôt que d'être des guillemets (tout comme stropping): la valeur de __foo est __foo (qui est réservée), pas foo (mais dans un espace de noms différent).
La seule contrainte difficile en C est qu'il n'y a pas d'espaces de noms. Par conséquent, vous devez trouver un moyen de rendre la fonction rename()
de votre bibliothèque système de fichiers distincte de la fonction rename()
de votre média = bibliothèque. La solution habituelle est un préfixe, tel que: filesystem_rename()
et media_rename()
.
L'autre conseil général est: rester cohérent au sein d'un projet ou d'une équipe. La lisibilité sera améliorée.
SI VOUS CHERCHEZ UN FORMAT GLOBALEMENT ACCEPTÉ
MISRA/JSF/AUTOSAR couvre près de 100% de toutes les normes de l'industrie pour nommer et organiser le code C/C++. Le problème est qu'ils ne seront pas disponibles gratuitement, c'est-à-dire que chacun des guides coûte de l'argent. Je sais que le livre standard de codage MISRA 2008 C/C++ coûte probablement environ 50 USD.
Vous pouvez les considérer comme le référencement Harvard pour la bibliographie et la lecture supplémentaire lorsque vous écrivez un journal. J'ai utilisé MISRA et c'est un bon moyen de nommer vos fonctions et variables, et de les organiser pour une utilisation appropriée.
SI VOUS CHERCHEZ QUELQUE CHOSE DE TEMPORAIRE
Les références que vous avez fournies pour Python et Java sont correctes je suppose. J'ai vu des gens adopter le style javadoc pour commenter, nommer et organiser le code. En fait, en fait, dans mon dernier projet, j'ai dû écrire du code C++ dans des fonctions/noms de variables de type Java. Deux raisons derrière cela:
1) C'était apparemment plus facile à suivre.
2) Les exigences du code de production n'ont pas touché le fond des normes de systèmes logiciels critiques pour la sécurité.
3) Le code hérité était (en quelque sorte) dans ce format.
4) Doxygen a permis de commenter la Javadoc sytle. À ce moment, nous utilisions doxygen pour générer de la documentation pour les gars de la production.
De nombreux programmeurs seront opposés à cela, mais personnellement, je pense qu'il n'y a rien de mal à adopter le nom de fonction/variable de style javadoc en C/C++. OUI, bien sûr, les pratiques d'organisation de votre contrôle de flux, la sécurité des threads, etc. doivent être abordées indépendamment. Cependant, je ne suis pas un candidat ici. Je ne sais pas non plus à quel point vos exigences de format de code de production sont strictes. Sans le détourner vers un domaine hors sujet, je vous suggère de revoir vos exigences, de savoir dans quelle mesure vous dépendez d'une convention de dénomination spécifique et de choisir une solution mentionnée dans la mienne et dans les réponses des autres.
J'espère que cela a aidé!?
Peu de choses importantes à considérer lors de la dénomination seraient;
Regardez le type actionObject ou ObjectAction. (Objet pas pour C. Mais en général quand vous allez dans d'autres langages orientés objet) Cela devrait aider
Le reste serait CONSTANT, court et descriptif à coup sûr.
La plupart des réponses sont bonnes, mais je veux dire quelques choses sur les conventions de dénomination pour les bibliothèques et les fichiers inclus, similaires à l'utilisation d'espaces de noms dans d'autres langages comme C++ ou Java:
Si vous créez une bibliothèque, trouvez un préfixe commun pour vos symboles exportés, c'est-à-dire les fonctions globales, les typedefs et les variables. Cela empêchera les conflits avec d'autres bibliothèques et identifiera les fonctions comme provenant de la vôtre. Ceci est un peu d'applications notations hongroises.
Peut-être aller encore plus loin et regrouper vos symboles exportés: libcurl utilise curl_ * pour les symboles globaux, curl_easy_ *, curl_multi_ * et curl_share_ * pour les différentes interfaces. Ainsi, en plus d'utiliser curl_ * pour toutes les fonctions, ils ont ajouté un autre niveau d '"espaces de noms" pour les différentes interfaces: appeler une fonction curl_easy_ * sur une poignée curl_multi_ * semble désormais incorrect, voir les noms de fonctions sur http: //curl.haxx.se/libcurl/c/
En conservant les règles pour les symboles exportés, vous devez les utiliser pour les fonctions statiques dans #include
ed files: essayez de trouver un préfixe commun pour ces fonctions. Peut-être que vous avez des fonctions utilitaires de chaîne statique dans un fichier appelé "ma_string"? Préfixez toutes ces fonctions avec my_string_ *.