Although the C language has been around for close to 30 years, its appeal has not yet worn off. It continues to attract a large number of people who must develop new skills for writing new applications, or for porting or maintaining existing applications. This article has been written with the needs of the developer in mind, and offers suggestions that may help them in their job.
Every company I’ve worked for has had their own style guidelines. Some were similar, some were not.
To confound things even further, I have my own personal style guidelines for my own projects.
How about the rest of you out there?
I work mostly in C++, but I’ve experienced the same problem (and much worse).
Most places used fairly similar coding standards. The main differences were in how they chose to identify member variables and method parameters. I’ve seen some differences in spacing and placement of the open ‘{‘. Generally, I’ve never had problems adjusting as long as there was a coding standard.
In my view there isn’t one perfect standard (3,4,8 spaces per tab, { on same or next line). What really matter is that developers adhere to the standard.
The worst I’ve ever seen is when a company/development team didn’t have a coding standard. Of course, the first thing I tried to do when I got there was create one. We even held a meeting where we voted on the elements of the standard. I was amazed at the level of resistance by the older C hacks on the team to ANY standard.
and since then, unless the language has some sort of whitespace rules, I pretty much keep as close to what python does.
Python is by far one of the easiest languages to understand, and definitely the pretiest. I find when coding in other languages I set up my editor to use Python-style whitespace. I wish more languages would use whitespace and colons instead of those annoying curly bracket things. Python-style coding is the way to go in ANY language.
What’s with “for (i=0 to 100)”, could these people use a little brush-up on the language?
Routinely turn off buffering for stdout? Ideally this could be the first statement in the main program. I don’t think so!
Don’t test “if (func())” because it may change someday from returning true on success to returning 0 … instead, test “if (func() != FAIL)!” At first, this sounds like a point on which reasonable people might differ, but when it gets to suggesting an alternative, it loses. If you’re planning for a change in the sense of the function return, you really have to account for the possibility that either failure or return may be represented by more than one value, so you need a function or macro to test the return value for success (as they do right after for strcmp.) If that seems silly (as it probably should), then expect the documented return values.
Some of this stuff is OK, but not enough to be worth reading. Read the Berkeley KNF or AT&T Indian Hill standards.
My current night-mare involves the maintenance of code that has been written-on since the mid to late 80’s. Some in C, some in C++ (very old C++), some in Clipper (mainly 5.01a, but there is some 5.0 and some Summer ’87 in there). You can read down the code and see where the individual developers worked on it. I’m not talking a few small source files either. We maintain about 1 million lines of source code for these old apps! It can get very difficult at times.
The funny thing is, the longer I work on this stuff, the easier it gets for me to spot an individual developer, just by his/her coding style!
There was an attempt to standardize the coding, but it occured way after the majority of the apps were written. Newer code in the old modules adheres to the standards, but the older stuff doesn’t. We’re not supposed to modify it either, because we might introduce bugs into otherwise working code.
Personally, I think COBOL is easier to read than Python. Don’t get me wrong, Python is a great language and I love its syntax but COBOL is much easier to read.
Nice article, but never usually worried about these things. I run “indent” over my C code in a UNIX environment, it has many pretty options to have your code indented as you exactly want it…
Actually, I find Perl to be easier to read. But then again, I am somewhat of a masochist! 😉
The advice for dealing with bodyless loops was somewhat odd:
The null body of a for or while loop should be alone on a line and commented so that it is clear that the null body is intentional and not missing code.
Their suggestion is then:
while(condition)
; /* VOID */
… which I find less readable and a bit more confusing than:
while(condition);
Another area which didn’t seem to be addressed very well was the use of goto. From the article:
goto should be used sparingly. The one place where they can be usefully employed is to break out of several levels of switch, for, and while nesting, although the need to do such a thing may indicate that the inner constructs should be broken out into a separate function.
This does not cover at all the use of goto for error handling, especially when building up a “stack” of operations to return everything to its original state before a function invocation in event of an error. For example:
if(!(p = alloc()) goto err0;
if(!(p->cxn = alloc()) goto err1;
if((p->cxn->fd = open(…)) < 0) goto err2;
return p;
err2:
close(p->cxn->fd);
err1:
free(p->cxn);
err0:
free(p);
return 0;
It seems to me that too often people are brainwashed by their professors and peers chanting “goto is bad… goto is bad” without giving a great deal of thought to the matter itself, and consequently error handling code from such people grows increasingly more convoluted as the state needing to be dismantled in the event of an error also grows more complicated. Furthermore, getting complete branch coverage on all error handlers during testing is usually impossible, so keeping as much code in common between the error handlers and keeping the specific portions of each as simple as possible becomes quite important.
Knuth wrote an excellent paper on the use of the goto statement, available at http://pplab.snu.ac.kr/courses/PL2001/papers/p261-knuth.pdf
I don’t care what tab equals when i code, but i ALWAYS use tab to indent to the current depth (i never mix with spaces), but will use only spaces after I reach said indentation. This means that no matter what editor i use, my code is always indented consistently, and if i am say setting up a bunch of variables by hand, i can align them for readability, etc.
Looks like a lot of this is straight out of the Indian Hill Style Guide.
The error on for syntax made me chuckle too.
>Routinely turn off buffering for stdout? Ideally this could be the first statement in the main program. I don’t think so!
Well, if it is only for debugging purpose..
I do it quite frequently to have the “correct” order between output from stderr and stdout.
I don’t allow the tab character into my code. Ever. All my indentation uses only spaces (three spaces per indent level). Tabs make it way to easy to write code that looks right under one editor configuration but is strung out all over the place on another. Since every text editor on Earth treats space characters the same way, I know my code will be appear correctly formatted, no matter what. (editors that don’t use fixed-width character fonts don’t count, as they are really just glorified word processors :^))
This has been my experience too (though I personally prefer 4 spaces per indent). Most decent editors allow you to set them to fill in n spaces instead of tabs (CodeWright, Visual SlickEdit, MS VC++). This is especially nice when dealing with debuggers (many of which view tabs as 8 spaces).
Since every text editor on Earth treats space characters the same way, I know my code will be appear correctly formatted, no matter what.
Three or four spaces is a reasonable compromise. A problem arises in that different people prefer varying degrees of indentation. Using true tabs allows for configurability (I prefer tabs display as 4 spaces) at the cost of a single, universal formatting which will display “properly” in any fixed-width editor.
To those who are saying the issue is moot because you can simply run the code through the beautifier of your choice, I certainly hope I never have to work on a CVS project with you…
I like doing this as well. My theory is that others can set their tab character to equal x number of spaces (where x is their preferred indent size) and I can leave mine at 8, and everyone will be happy. My belief is that through extreme formatting anality I can make this work.
Another thing that I’ve read elsewhere is ‘always use pre-increment instead of post-increment’ i.e. use ++i instead of i++. What I haven’t read is an explanation of just why pre-increment is better than post-increment. Personally, I use post-increment merely because it looks prettier
Another thing that I’ve read elsewhere is ‘always use pre-increment instead of post-increment’ i.e. use ++i instead of i++. What I haven’t read is an explanation of just why pre-increment is better than post-increment.
I’ve heard this “rule” cited before (specific to C++) for the following performance reasons:
The semantics of postincrement include making a copy of the value being incremented, returning it, and then preincrementing the “work value”. For primitive types, this isn’t a big deal… but for iterators, it can be a huge issue (for example, some iterators contains stack and set objects in them… copying an iterator could invoke the copy ctor’s of these as well). In general, get in the habit of always using preincrement, and you won’t have a problem.
Of course, this makes no difference in C…
I remember post-increment is less efficient because the compiler has to construct and return an object containing the original value… So if you don’t need to use the original value, prefer pre-increment instead.
Anyway, I use post-increment also, I’m so used with it than I don’t think it’s even possible otherwise 🙂
realy, it is a silly discussion since pre-incriment’s time complexity is constant, and post incriment’s time complexity is constant.
and if you are using them in an iterator, it will not have any real effect on your iteration since an iterations time complexity is O(N) and is so much more complex than the incrimnet/decriment, the pre/postfix of your iterator has almost no effect on the performance.
…and can make everybody happy, if you use them in such a way that the “lining-up” is preserved.
Use tabs for the basic indentation of the level of scope.
/* Level 0 */
void foo(int blahblah)
{
(TAB)/* level 1 */
(TAB)if ( blahblah == KITTYCAT ) {
(TAB)(TAB)/* level 2 */
(TAB)(TAB)meow();
(and so on)
That way, if people like their indentation width to be 4, they get 8! Until they change their editor’s configuration. Then they get 4, and are at peace with the universe 🙂
Now, if you have non-whitespace, such as the name of a function for a call, and you want to line things on a lower line up with a character that comes after the first non-whitespace character on this line (sorry if this is a bad description), you once again use tabs for the scope, and then you use spaces to get to the point you want to line up with. For example:
(TAB)FunctionWithALotOfArguments(firstFoo, firstBar, something_awesome,
(TAB)(SPACES…) and_the_rest);
That way, things stay lined up no matter what tab-width you love.
On the last line of code in my previous post, and_the_rest should have lined up with the first ‘s’ in something_awesome. Heh heh
Try:
if(p = alloc()) {
if(p->cxn = alloc()) {
if((p->cxn->fd = open(…)) < 0) {
return p;
} else {
close(p->cxn->fd);
} else {
free(p->cxn);
};
} else {
free(p);
};
return 0;
I do question your close() code… If the open() field, then why are you trying to close it.
Try such a structure with MS COM calls, where every other statement is of type
hr = foo();
if (FAILED(hr))
…
It gets darn ugly. It’s much easier to send every failed call to an exit routine to free up variables. Sometimes, you might have a dozen COM calls in one method. That would make some UGLY indentation. 🙂
Aah, a goto hater has taken up my challenge.
Yes, you are correct, my entire “stack” is misaligned. err0 should simply return 0, and what the err2 label is now should be err3 and utilized for another error condition which occurs at a level higher than the open statement.
You are taking Dijkstra’s suggested approach and utilizing nesting. However, while this works at three levels, the deeper you go the uglier the code gets. While this does eliminate the use of goto, the price quickly becomes code readability. Nesting is not, in my opinion, a more readable solution than goto.
Nesting works of course, it’s just ugly.
You know, they are not the same thing. If you need postincrement, you can’t do with preincrement just like if you need preincrement, you can’t do with postincrement. If and only if you are not interested in the return value of the operation, and you just want an increment you can use either one. Then your compiler should detect the internal dead code which returns the object before increment operation only to discard right away and optimize it, which makes cost of pre and post increment the same. If it doesn’t, stay away from that compiler at all costs. Even gcc can handle those.
And if you don’t already know this, you have no bussiness coding. Go play with VB or something, leave C/C++ alone.
I have one quick rant, I really hate not having function names start with a capital letter. For me, this allows me to tell immediately if I have a function pointer vs calling a function by name. Just my opinion. (Yes, I realize that a function is in essence an address, but I have code that uses/passes function pointers extensively.)
Sorry, you guys are wrong. Ruby is the most beautiful language out there But seriously, I think it looks really clean (and is a great language, give it a try if you haven’t yet)
What makes Ruby cleaner than Python? The little Ruby I’ve seen seems overall a little messier, but has certain improvements over Python. Like using !’s to say it’s mutating something; I wish Python had that.
But there’s the Perlisms like $ and @.
http://www.cs.kun.nl/~clean/
it is always nice when some one gets over zealous to stroke their brain.
if you follow the context of the entire thread, you will see that this entire discussion was with regards to iteration and nothing more.
I can found most things of this article in “C traps and pitfalls”. Even many “same” examples. And the author are different.
Most things in this article can be found in “C traps an pitfalls”, and many examples are the same. But author are different.
Many C programmers ( like me ) often try to avoid deep nesting by using “goto” and “break”, “continue” As :
for (I=0;I<10;I++) {
if (T[i]==0) {
// Big chunk of code, 2 deep identation
}
}
Can be replaced by :
for (I=0;I<10;I++) {
if (T[i]!=0) continue;
// Same big chunk of code
}
continue is just a special case of goto statement.
“Personally, I think COBOL is easier to read than Python. Don’t get me wrong, Python is a great language and I love its syntax but COBOL is much easier to read.”
Your kidding right? COBOL is horrible, and the fact that you have to start in certain columns (rememisant from the punch card days of programming which is sad it’s still in COBOL) and are restricted to how far your code can go out is sad. So many times i’ve written COBOL code that has to be adjusted because the line goes out just a litter further than column 71. Aside from COBOL being a horrible language itself, the formatting your forced to apply doesn’t help. The only advantage COBOL has is that it’s english like, aside from that it has nothing but disadvantages.