C/C++ Programming Style Guidelines Fred Richards StyleguidelinesandprogrammingpracticesforC/C++codefor DynamicSoftwareSolutions. Usethechecklistattheendofthis documentpriortosubmittingcodeforpeerreview. “Degustibusnonestdisputandum. ” 1. Introduction ThisdocumentcontainstheguidelinesforwritingC/C++codeforDynamicSoftware Solutions. Thepointofastyleguideistogreateruniformityintheappearanceof sourcecode. Thebenefitisenhancedreadabilityandhencemaintainabilityforthe code. Whereverpossible,weadoptstylisticconventionsthathavebeenprovedto contributepositivelytoreadabilityand/ormaintainability. Beforecodecanbeconsideredforpeerreviewtheauthormustcheckthatitadheresto theseguidelines. Thismaybeconsideredaprerequisiteforthereviewprocess. A checklistisprovidedattheendofthisdocumenttoaidinvalidatingthesourcecode’s style. Wherecodefailstoadheretotheconventionsprescribedheremaybeconsidered adefectduringthereviewprocess. Ifyouhavenotalready,pleasestudyCodeCompletebySteveMcConnell. Thisbook providesadetaileddiscussiononallthingsrelatedtobuildingsoftwaresystems. Italso includesreferencestostatisticalstudiesonmanyofthestylisticelementsthataffect programmaintainability. Anothervaluablesourceofsolidprogrammingpracticetipsis ThePracticeofProgrammingbyBrianW.KernighanandRobPike. ScottMeyers’ 1 C/C++StyleGuide books,EffectiveC++andMoreEffectiveC++shouldbeconsideredrequiredreading foranyC++programmer. AndwhatpersonwouldbeconsideredcompletewithouthavingreadTheElementsof StylebyStrunkandWhite? 2. File Contents Usefilestogroupfunctionality. Eachfileshouldcontainonlyonecohesivesetof functions. Avoidduplicatingfunctionalityinseparatefiles. Ifdifferentfilescontain similarfunctions,considergeneralizingthefunctionsufficientlyandputtingitintoits ownfilesothatbothfunctiongroupscanusetheonesource. ForC++code,putonly oneclassorcloselyrelatedsetofclassesineachfile. Avoidstrongcouplingbetweenfunctionsandclassesimplementedinseparatefiles. If twoobjectsaresostronglycoupledthatonecanonlybeusedinconjunctionwiththe otherthentheybelonginthesamefile. Useheaderfiles(.hsuffix)todeclarepublicinterfaces,usecodefiles(.c,.ccor.cpp suffix)todefineimplementations. Typicallyeachcohesivesetoffunctionsyouwritein asinglefilewillhaveoneaccompanyingheader/interfacefilepair. Codethatusesyour implementationwill#includetheheaderfile. Beprecisewith#includestatements. Explicitlyincludethe.hfilesyourequire,and onlywhereyourequirethem. If,forexample,yourcodecallsafunctiondefined externally,includethatfunction’sassociated.hinyourimplementationfilenotinyour code’sassociated.hfile. Youshouldonlyneedtoincludeotherfilesinyour.hfileif yourpublicfunctioninterfaceordatatypedefinitionsrequirethedefinitionscontained therein. Avoidusingheaderfilestocontainasetof#includedirectivessimplyfor convenience. This“nesting”of#includeconstructsobscuresfiledependenciesfrom thereader. Italsocreatesacouplingbetweenmodulesincludingthetop-levelheader file. Unlessthemodulesarecohesivelycoupledfunctionally,andeachrequiresall the .hfilesincludedintheconvenienceheader,itispreferabletoinsteadincludeallthe 2 C/C++StyleGuide individual.hfileseverywheretheyarerequired. 2.1. Header (Interface) File Content Headerfilesshouldcontainthefollowingitemsinthegivenorder. 1. Copyrightstatementcomment 2. Moduleabstractcomment 3. Revision-stringcomment 4. Multipleinclusion#ifdef (a.k.a. "includeguard") 5. Otherpreprocessordirectives,#include and#define 6. C/C++#ifdef 7. Datatypedefinitions(classesandstructures) 8. typedefs 9. Functiondeclarations 10. C/C++#endif 11. Multipleinclusion#endif Example1. Standard(C)headerfilelayout /* * Copyright (c) 1999 Fred C. Richards. * All rights reserved. * * Module for computing basic statistical measures on * an array of real values. * * $Id$ */ 3 C/C++StyleGuide #ifndef STATISTICS_H #define STATISTICS_H #include <math.h> #include <values.h> #define MAXCOMPLEX { MAXINT, MAXINT } #ifdef _cplusplus extern "C" { #endif struct complex { int r; /* real part */ int i; /* imaginary part */ }; typedef struct complex Complex; ... /* * Compute the average of a given set. * Input - array of real values, array length. * Output - average, 0 for empty array. */ float ave(float* v, unsigned long length); ... #ifdef _cplusplus } #endif #endif /* STATUS_H */ 4 C/C++StyleGuide 2.2. Code Files CandC++codefilesfollowasimilarstructuretotheheaderfiles. Thesefilesshould containthefollowinginformationinthegivenorder. 1. Copyrightstatementcomment 2. Moduleabstractcomment 3. Preprocessordirectives,#includeand#define 4. Revision-stringvariable 5. Othermodule-specificvariabledefinitions 6. Localfunctioninterfaceprototypes 7. Class/functiondefinitions Unlikeintheheaderfile,theimplementation-filerevisionstringshouldbestoredasa programvariableratherthaninacomment. Thiswayidentwillbeabletoidentifythe sourceversionfromthecompiledobjectfile. ForCfilesuse: static const char rcs_id[] __attribute__ ((unused)) = "$Id$"; The__attribute__modifierisaGNUCfeaturethatkeepsthecompilerfrom complainingabouttheunusedvariable. Thismaybeomittedfornon-GNUprojects. ForC++files,usethefollowingformfortherevisionstring: namespace { const char rcs_id[] = "$Id$"; } Precedeeachfunctionorclassmethodimplementationwithaform-feedcharacter (Ctrl-L)sothatwhenprintedthefunctionstartsatthestartofanewpage. 5 C/C++StyleGuide Example2. Standard(C++)implementation/codefile // // Copyright (c) 1999 Fred C. Richards. // All rights reserved. // // Module for computing basic statistical measures on // an array of real values. // #include "Class.h" #include <string> namespace { const char rcs_id[] = "$Id$"; } // Utility for prompting user for input. string get_user_response(); ^L Class::Class(const int len) { private_array_ = new[len]; } Class::~Class() { delete private_array_; } ^L ... 6 C/C++StyleGuide 3. File Format TheformattingstylepresentedhereisessentiallythatusedbyStroustrupinTheC++ ProgrammingLanguage. IfyouuseEmacsyoucanmakethisyourdefaultediting modebyaddingthefollowingtoyour.emacsfile: (defun my-c-mode-common-hook () (c-set-style "stroustrup")) (add-hook ’c-mode-common-hook ’my-c-mode-common-hook) Formatyourcodesothatthespatialstructureillustratesthelogicalstructure. Useblank linestohelpseparatedifferentideas,useindentationtoshowlogicalrelationships,and usespacestoseparatefunctionality. Eachblockofcodeshoulddoexactlyonething. Startallfunctiondefinitionsanddeclarationsincolumnzero. Putthereturnvaluetype, thefunctioninterfacesignature(nameandargumentlist),andthefunctionbodyopen bracketeachonaseparateline. Forfunctionsthataremorethanafewlineslong,put thefunctionnameaftertheclosingbracketinacomment. Example3. Formattingfunctiondeclarationsanddefinitions void debug(const string& message); int Class::method(const int x, const string& str) { . . . } // method 7 C/C++StyleGuide Useasinglespacetoseparatealloperatorsfromtheiroperands. Theexceptionstothis rulearethe“->”,“.”,“()”and“[]”operators. Leavenospacebetweenthese operatorsandtheiroperands. Whenbreakingoperationsacrosslines,puttheoperator attheendofthebrokenlineratherthanatthestartofthecontinuationline. Usefourspacesforeachlevelofindentation. Avoidmakinglineslongerthan80 characters. Whenbreakinglines,usethenaturallogicalbreakstodeterminewherethe newlinegoes. Indentthecontinuationlinetoillustrateitslogicalrelationshiptotherest ofthecodeintheline. Forfunctions,forexample,thismeansaligningargumentswith theopeningparenthesisoftheargumentlist. Example4. Breakingstatementsacrossmultiplelines new_shape = affine_transform(coords, translation, rotation); if ( ( (new_shape.x > left_border) && (new_shape.x < right_border) ) && ( (new_shape.y > bottom_border) && (new_shape.y < top_border) ) ) { draw(new_shape); } Useapure-block,fullybracketedstyleforblocksofcode. Thismeansputbrackets aroundallconditionalcodeblocks,evenone-lineblocks,andputtheopeningbracketat theendofthelinewiththeopeningstatement. Theexceptiontothisruleisfor conditionsthatarebrokenacrossmultiplelines. Inthiscaseputtheopenbracketona linebyitselfalignedwiththestartoftheopeningstatement(asshownabove). Example5. Fullybracketed,pureblockstyle if (value < max) { if (value != 0) { func(value); } 8 C/C++StyleGuide } else { error("The value is too big."); } Althoughthebracketsmayseemtediousforone-lineblocks,theygreatlyreducethe probabilityoferrorsbeingintroducedwhentheblockisexpandedlaterinthecode’s life. 3.1. Unique to C++ Startpublic,protected,private,andfriendlabelsincolumnzeroofclass declarations. Useexplicitpubliclabelsforallstructpublicfieldsanduseexplicit privatelabelsforallprivateclassmembers. Themembersofaclassshouldbedeclaredinthefollowingorder. Declareallpublic datamembersandtypedefinitionsfirst. Declareprivateorprotecteddatamembersor typedefinitionsusedinfunctionmemberinitializationlistsorinlineimplementations next. Declareallpublicmemberfunctionsnext,startingwiththeconstructorsand destructor. Declareallremainingprivateorprotecteddatamembersandtypedefinitions next. Declareallprivateorprotectedfunctionmembersnext. Declareallfriendslast. Putsimpleinlinefunctiondefinitionsonthesamelineastheirdeclaration. Forinline functionsspanningmultiplelines,useapure-blockstylewithfour-spaceindentation. Ingeneral,avoidputtingcomplexfunctionimplementations.hfiles. Example6. Classdeclarationformat class Type : public Parent { private: int x_; int y_; public: Type(); Type(int x) : x_(x) { } ~Type(); 9 C/C++StyleGuide int get_x() const { return x_; } void set_x(const int new_x) { x_ = new_x; } ... void display() { ... } } 4. Choosing Meaningful Names 4.1. Variable Names ThenameformattingconventionsdescribedhereareessentiallytheGNUcoding standards. Theseareavailableonlineusinginfo. Uselowercaseforallvariablenames. Formulti-wordnames,useanunderscoreasthe separator. Useallcapitalsforthenamesofconstants(i.e. variablesdeclaredconstand enumeratedtypes). Useanunderscoreasawordseparator. Choosevariablenamescarefully. Whilestudiesshowthatthechoiceofvariablenames hasastronginfluenceonthetimerequiredtodebugcode,thereareunfortunatelyno clearandfixedrulesforhowtochoosegoodnames. ReviewChapter9ofCode Completeperiodically. Inthemeantime,herearesomegeneralguidelinestofollow: • Beconsistent! Themostimportantthingistoestablishaclear,easilyrecognizable patterntoyourcodesothatotherswillbeabletounderstandyourimplementation andintentasquicklyandreliablyaspossible. • Usesimilarnamesforsimilardatatypes,dissimilarnamesfordissimilartypes. 10