Best Practices for Programming in C
An anonymous reader writes "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 provides a set of guidelines that can help you with your coding."
Although the C language has been around for close to 30 years, its appeal has not yet worn off.
I'm sure that in some ways that statement may be true, but I've been trying for MONTHS to get people interested in the C/C++ Meetups! Compared to Python you'd think we were trying to start a Sanskrit study group!
btw..fp? hee hee!
Quod scripsi, scripsi.
to improve productivity while coding C is to use TFT LCD monitors, preferably 19 inch ones. They releive the eye-strain and greatly improve productivity.
From the article:
for(i=0 to 100)
array[i]=0
Maybe I missed something but since when is that C?
I think C is only still alive because it is supported on most systems, and most programmers don't have enough training to use a more complex language.
C is really just glorified assembly language. It only provides a minimal of type checking over most macro assemblers and is about as easy to read. It does have alot of operators to save typing though.
I think that C and 'C++ used as C' is the reason alot of commercial software is so bug ridden. Hopefully Java, .NET/.GNU, scripting languages and competent use of modern C++ are starting to change that.
Don't even get me started on the 'C is faster than C++ myth'. Only in the hands of an idiot.
/..sig file not found - permission denied.
Whitespace
"When a ball dreams, it dreams it's a frisbee"
If you reply, do so only to what I explicitly wrote. If I didn't write it, don't assume or infer it.
(please note: I'm still learning C) So what should I be using instead of scanf? The article recommends against it, but doesn't say whether there is a better way to get some input and get interesting chunks out of it.
I do not have a signature
Here is a much better article about coding practices. It also covers broad topics, not just C in specific.
Dont programm in C unless you have a really good reason to.
Good reasons are:
- You are extending an operating system kernel or other huge system that is written in C.
- You are writing a library and expect it to be used from several other languages. C is the lowest common denominator, every language has a C interface.
In all other cases, use a high-level language. Users and admins will be grateful for not having to download patched versions every time a buffer overflow or format-string error is found. You will like being able to concentrate on the core problem you want to solve instead of dealing with all the detail C and its libraries left for you to care about. If you need speed, use a high-level language with a good compiler. If you need to bit-fiddling, use a high-level language with good bit-fiddling support. They exist, and there's even some overlap between them.Programming can be fun again. Film at 11.
This article really does not say anything that any decent programmer does not know. Why we need an article to tell us the basic rules of C is beyond me.
1. Indent properly.
2. Make your code readable.
3. Use good variable names.
4. Avoid buffer overflows.
5. Avoid using statements like goto.
They missed the most basic rule of them all though, convert to C++.
Apparently it was too obfuscated for IBM. The first code example is missing a } at the end of the line.
=================
Unix is very user friendly, it's just picky about who its friends are.
FYI, the article seems to be something like a company "basic C coding standards" rather than anything to do with what I understand as "best practices"; maybe a coding tips sheet for an introductory C programming class.
Larry
For example, for the C program that I'm writing right now, I decided to use GLib -- the base utillity library used by GTK.
I initially chose it for portability reasons, but soon discovered it had a wealth of cool stuff in it. In addition to providing the standard data structures (trees, hashes, linked lists), it also has a string type ( GString, ) which handles a lot of the string issues that C programmers get bogged down with.
A lot of the gotchas (buffer overflows, et. al.) mentioned in this article have to do with these string issues, and using GLib's GString data type has enabled me to avoid those.
There is another library similar to GLib, The Apache Portable Runtime, used in the Apache webserver, and also in Subversion.
In addition to all this, I'm using XML as the storage format for my program, mostly because libxml takes care of the file parsing issues so I don't have to.
Bottom line, choose your libraries carefully, they can make a world of difference.
Thomas
Oh what enlightenment!
- When you've learned all there is to know about C, find out how to simplify it a bit in C++. Notice the job security and look of awe when you master the ++.
- After mucking around in these low-density languages, step up to Perl and see how a language built by a task-oriented person stomps one built by a system-oriented person. See your project file sizes shrink before your very eyes!
- Now take your newfound magic ability to learn new languages and apply it to whipping out pages with PHP and MySQL for all your friends quickly! You'll be the talk of the C crawlers crowd! Hey! Gimmie some content! Aw, forget it - let me just play!
- Now plumb the depths of (supposed) machine-independent laguanges by writing some Java and finding out what "Sun-certified" means! (hint: Sun owns it)
- Optional: Head back to school to get a PhD in autoprogramming theory and self-construction methods. Sequester yourself away to your dorm room for endless hours of experiments training a neural net to convert tasks to code using the most efficient method possible.
- Finally, wrap up your technical life by examining all these related language nuances holistically and achieve the zen of programming: "there is no language"
I thought you could use NULL to calculate structure offsets, so with something like
struct _x {
int a;
int b;
}
it was legal to say &(((struct _x *)NULL)->b)
to figure out the offset of b within the structure?
So I agree, it seems like pretty basic tips, not any sort of "best practices" thing.
- adam
You can find many more of these here...
pb Reply or e-mail; don't vaguely moderate.
I suggest slashdot change their name to shitdot. Because they have day-old shit, and that's just the front page.
don't right code that sucks.
...it also has a string type ( GString, ) which handles a lot of the string issues...
G-String?? Could they have come up with a different name for that type of string? Issues like butt-flossing and the like..
http://github.com/gbook/nidb
What I want to see is material on setting up a project in an intelligent way.
I've got Lakos' book, but there just isn't much out there on non-trivial stuff.
How about articles that show intelligent uses of CVS, Doxygen, and autotools?
What about using C++, boost.python, mod_python, and apache for that killer website?
Get thee glass eyes, and, like a scurvy politician, seem to see things thou dost not.--King Lear
But code that sucks *should* be righted...
I want to drag this out as long as possible. Bring me my protractor.
Consider C++: you can screw up in all the ways you can screw up with C, and many more besides. I don't think anybody would consider C++ a low-level language.
I actually agree with your point. I'd just express it differently: C supports the kind of low-level tweaking most programmers shouldn't bother with any more. You should avoid C unless you really need to do this stuff. Otherwise, use a language/library combination that does the low level stuff for you, and probably does it better than you could.
This could be rewritten as:
I believe this is clearer, and less error prone.Although the C language has been around for close to 30 years, its appeal has not yet worn off
UNIX is the same age, and it hasn't stopped people from thinking that UNIX-like operating systems are the pinnacle of good design.
I'm an electrical engineer first and a programmer second. I write everything from BIOS-esque firmware clear up to applications that do data analysis from huge mainframe databases for my company. My language of choice? As close to ANSI C as I can get, though usually I get lazy and use some GNU extensions.
Now, why on earth would I do something like that? Just to piss off the comp sci types around me? Well, no, but that's a nice side effect.
Reasons I love/use C:
- It IS glorified assembly. As such, the compiler tries to be minimally helpful and just lets me do what I want to do.
- It doesn't allow OOP crap. I won't argue that OOP doesn't have its place, somewhere, but that place isn't in anything I've needed to build yet.
Why do I hate OOP so much? First and foremost I find it only a tool of obfuscation in the stuff I write. It's much easier to debug procedural code by just following the execution path than wondering what the hell the object that was just instantiated invoked in the constructor, etc. Too much jumping around in the code - basically causes me to forget to look, because it's not intuitive. Same exact reason I hate FORTH (but I'm still fluent in it anyway). I'd rather just have an initializer function called immediately following the declaration of a new variable than having behaviours tacked on.
- C is faster than C++ if you do everything according to the OOP model that C++ leads you toward. I guarantee my pointer math blows away any "safer" solution in terms of raw speed. It's also just as safe, because all the inputs are bounds checked once so I know they can't exceed certain limits. However, for intelligent mixes of OOP-model code and C-style fun, there's no significant speed difference.
- Also, C is standard. C is everywhere. I can use it (with code appropriate to the task) on everything from a PIC12xxx series part clear up to our IBM big iron (though that lack of curly braces it quite annoying). As long as I hang out close to ANSI, my code tends to be very portable. As such, I have a library that is used on everything from small, embedded M68k-series processors up to 16-proc Unix boxes and even larger yet mainframes. Completely threadsafe, no memory leaks, and very, very portable.
Basically, don't use bloat-o-language unless you have a good reason. Remember - CPUs still essentially execute one instruction at a time, mostly in order. Programming is all about moving register 1 to register 2, possibly while performing an arithmetic operation involving register 3.
I would assert that inappropriate use of OOP model programming, a complete disregard for effeciency in the face of beauty-of-design, and an unholy fascination with language du jour has lead to the sorry, bloated, buggy, slow state of modern applications. IMHO, OOP has lead us down this path, without buying us much. Much except the ability to hire less competent programmers to build their tiny chunk of the application, because everything's overdesigned and all the interfaces are pre-specified, because that's how humans would model the problem. Usually there's little regard for how a machine could best handle the problem.
atoi has undefined behavior for some error conditions. strtol is a safe version. You should only consider using atoi if you are entirely sure that the input is valid. And even then you should choose to use strtol to make the code rubust in the face of changes.
(For C++ heads, just read an int from a stream of whatever kind with >>, just as you do for any other type, and then check the stream status afterwards to make sure the operation succeeded, as in if (mystream >> myint) it_succeeded(); )
Buy a copy of "Code Complete". Scrawl "coding standards" on the front in big black marker. Live & breathe it.
A classic
Possibly, but he'd have to be a very good monkey. Many instruction sets and processor architectures are so complex now that writing things the "intuitive" way in assembler does not yield the optimal result. It takes a lot of specialist knowledge to get a good assembly implementation of non-trivial algorithms on such systems, and the best place for those specialists is... writing compilers. IOWs, Joe C Newbie may well get a better implementation of some common algorithm than the average assembler programmer, because Joe has John C Compiler on his side.
As for C against C++, right now, optimising compilers for C do better than for C++, and hence C is faster than C++-used-as-C, though the gap is closing as C++ optimising compilers catch up. OTOH, C++ has much more potential, principally because it supports higher level constructions like exceptions and polymorphism natively, and because templates are a tool for improving efficiency that C will never match. Overall, well-written C++ that uses the language's features effectively is already faster than similarly well-written C, and the gap is widening.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
And processing of large data volumes in a fairly straight forward manner is also very good to do in straight and "simple" code. And C is really good for that. (I'm think eg cryto code, which is both quite math intensive and highly sequential.)
I won't comment on your views on OOP, while I don't agree with them I don't think anything good will come out of the discussion. (The general idea with all higher level languages is however to map the language as closely as possible to the algorithms as possible. It becomes obvious when you compare eg sorting algorithms in different languages.)
Now this is just plain wrong. Perhaps you work mainly will micro-controllers but the types of CPUs that are in a typical PC today are not this easy to use at a low level.
First off,
Second, a typical PC today doesn't even execute x86 asm. It's translated internally to it's own micro code (typically more towards RISC) and executes that. Furthermore it is super-scalar and as such executes several instructions at once. It also moves code around and a bunch of things that will make your brain go numb if you start trying to optimize it by hand. Hell, you can't even access all the registers manually in many cases.
And that's just looking at the instructions. If you start taking the memory hierarchy into consideration then you'll soon find yourself in a world of confusion.
Fortunately compilers don't get confused by this. So the way I see it a big importance in the future will be not only how well a language maps to hardware and how it maps to the "algorithms". Of even bigger importance could be how clear things are to the compilers so they can do a proper job. (And in many cases C is very suitable for this today.)
Jeeze, there's nothing like taking a bunch of idosyncratic preferences and treating them as best practice, let alone enforcing them at a workplace.
I note that Pike doesn't even come close to labeling his piece "Best Practice For C Coding" - for which I thank him.
He does have points that are at least arguably valid, but he lost me at the end.
"Include files should never include files" ?! Pure bull-freaking-crap hogwash. Rather the opposite is the case! Every include file should include every dependency include file. And order dependency of include files is a no-no. It is quite easy to eliminate all order dependencies, and if I have a religious rule, this is it.
I think the best practice of C programming is to use it only when absolutely necessary. Otherwise, use modern language which will boost your productivity and make your applications easier to write and with fewer bugs (and no presence on Bugtraq due to a buffer overflow)
Everyone defends higher level things like Java, C# and other scripting languages on the basis that we should have tons of little dynamically allocated little objects floating around, and that you need to have a beefy memory manager floating around to deal with it.
Why do you have to have tons of tiny objects floating around? All that tiny little allocating over and over again just slows everything down, and probably makes your programs more complex. I say, screw dynamic allocation, just use big virtual memory backed vectors of fixed length structures. It's simpler, more reliable, and faster.
This is my sig.
I believe the most common names are:
() parentheses
[] square brackets
{} curly braces
<> angle brackets (although true angle brackets would have a less acute angle)
That way you can be accurate and people who don't know what the difference is will still understand you.
Maybe C coders just don't cotton to "meetups". Maybe newer languages are more likely to give rise to such things. Mayber newer technologies give rise to such things. Trying to have a C "meetup" today might be a lot like trying to re-create the Homebrew Computer Club or Woodstock.
Of course hardware hacking and Jimi Hendrix music still attract a lot of people. They just don't attract them in the same way.
For all intensive purposes, "whom" is no longer a word. That begs the question, "who cares"?
Where did it come from?
Does it mean ANYTHING different from"recommendations?"
Does anyone ever give any evidence that the "best practices" are actually best?
"How to Do Nothing," kids activities, back in print!
"Java is as fast as C++"
"C++ is as fast as C"
"C is as fast as assembly"
tell us some more funny ones santa claus.
Why write C when you can write assembler? After all your C compiler can't be as efficient as hand-tuned assembly!
You can draw this efficiency line ANYWHERE -- it is basically the language you learned on that you are predisposed towards and accept the runtime penalty for.
You sound like you learned C first -- mainly because you refer to OOP as crap and everything else as a "bloat-o-language." Realize that there is no one true language. Don't let yourself be defined by the tools you have at your disposal. Generally, you probably used classes in your applications without realizing it, and ironically while patting yourself on the back about not using them. You just didn't use the class keyword.
a complete disregard for effeciency in the face of beauty-of-design
Except that beauty of design often leads to efficiency and simplicity which drastically reduces the number of bugs. Beautiful designs are minimal, yet complete and impose very small overhead for their usage.
Usually there's little regard for how a machine could best handle the problem.
This is a really dangerous statement, almost as if you are justifying writing obscure code in the name of performance. Most C optimizers will do the necessary pointer arithmetic that you pride yourself on automatically. Software is written to be maintained by humans and be used by humans. The computer only executes it. A lot of requirements allow more code clarity over raw performance, and using a higher level language is an important step in that regard.
I am only a college student who is working my 5th or 6th summer doing programming work, and cannot fathom how a 'professional' can make statements like these.
Most languages have some kind of foreign function interface, so they can link to C/C++ libraries. Most languages have good mailing lists where, in some cases, even the designers of the language hang out to answer any questions you have and (if you're lucky) to take on board your suggestions for _improving_ the language.
And nearly all of them are more maintainable than C++ (which, as the saying goes, combines the power of Java with the readability of Brainfuck).
Java? Ruby? Perl? Ada? O'Caml?
In British English, make those
...and guess what...
() brackets
[] square brackets
{} curly brackets.