Current version

v1.10.4 (stable)

Navigation

Main page
Archived news
Downloads
Documentation
   Capture
   Compiling
   Processing
   Crashes
Features
Filters
Plugin SDK
Knowledge base
Donate
Contact info
Forum
 
Other projects
   Altirra

Search

Archives

01 Dec - 31 Dec 2013
01 Oct - 31 Oct 2013
01 Aug - 31 Aug 2013
01 May - 31 May 2013
01 Mar - 31 Mar 2013
01 Feb - 29 Feb 2013
01 Dec - 31 Dec 2012
01 Nov - 30 Nov 2012
01 Oct - 31 Oct 2012
01 Sep - 30 Sep 2012
01 Aug - 31 Aug 2012
01 June - 30 June 2012
01 May - 31 May 2012
01 Apr - 30 Apr 2012
01 Dec - 31 Dec 2011
01 Nov - 30 Nov 2011
01 Oct - 31 Oct 2011
01 Sep - 30 Sep 2011
01 Aug - 31 Aug 2011
01 Jul - 31 Jul 2011
01 June - 30 June 2011
01 May - 31 May 2011
01 Apr - 30 Apr 2011
01 Mar - 31 Mar 2011
01 Feb - 29 Feb 2011
01 Jan - 31 Jan 2011
01 Dec - 31 Dec 2010
01 Nov - 30 Nov 2010
01 Oct - 31 Oct 2010
01 Sep - 30 Sep 2010
01 Aug - 31 Aug 2010
01 Jul - 31 Jul 2010
01 June - 30 June 2010
01 May - 31 May 2010
01 Apr - 30 Apr 2010
01 Mar - 31 Mar 2010
01 Feb - 29 Feb 2010
01 Jan - 31 Jan 2010
01 Dec - 31 Dec 2009
01 Nov - 30 Nov 2009
01 Oct - 31 Oct 2009
01 Sep - 30 Sep 2009
01 Aug - 31 Aug 2009
01 Jul - 31 Jul 2009
01 June - 30 June 2009
01 May - 31 May 2009
01 Apr - 30 Apr 2009
01 Mar - 31 Mar 2009
01 Feb - 29 Feb 2009
01 Jan - 31 Jan 2009
01 Dec - 31 Dec 2008
01 Nov - 30 Nov 2008
01 Oct - 31 Oct 2008
01 Sep - 30 Sep 2008
01 Aug - 31 Aug 2008
01 Jul - 31 Jul 2008
01 June - 30 June 2008
01 May - 31 May 2008
01 Apr - 30 Apr 2008
01 Mar - 31 Mar 2008
01 Feb - 29 Feb 2008
01 Jan - 31 Jan 2008
01 Dec - 31 Dec 2007
01 Nov - 30 Nov 2007
01 Oct - 31 Oct 2007
01 Sep - 30 Sep 2007
01 Aug - 31 Aug 2007
01 Jul - 31 Jul 2007
01 June - 30 June 2007
01 May - 31 May 2007
01 Apr - 30 Apr 2007
01 Mar - 31 Mar 2007
01 Feb - 29 Feb 2007
01 Jan - 31 Jan 2007
01 Dec - 31 Dec 2006
01 Nov - 30 Nov 2006
01 Oct - 31 Oct 2006
01 Sep - 30 Sep 2006
01 Aug - 31 Aug 2006
01 Jul - 31 Jul 2006
01 June - 30 June 2006
01 May - 31 May 2006
01 Apr - 30 Apr 2006
01 Mar - 31 Mar 2006
01 Feb - 29 Feb 2006
01 Jan - 31 Jan 2006
01 Dec - 31 Dec 2005
01 Nov - 30 Nov 2005
01 Oct - 31 Oct 2005
01 Sep - 30 Sep 2005
01 Aug - 31 Aug 2005
01 Jul - 31 Jul 2005
01 June - 30 June 2005
01 May - 31 May 2005
01 Apr - 30 Apr 2005
01 Mar - 31 Mar 2005
01 Feb - 29 Feb 2005
01 Jan - 31 Jan 2005
01 Dec - 31 Dec 2004
01 Nov - 30 Nov 2004
01 Oct - 31 Oct 2004
01 Sep - 30 Sep 2004
01 Aug - 31 Aug 2004

Stuff

Powered by Pivot  
XML: RSS feed 
XML: Atom feed 

§ Religious issues (for programmers)

Anyone who's been coding C/C++ long enough in a group environment knows that there are two topics that should be treated like kryptonite:

If you're smart, you try not to bring these up for discussion unless you have a disaster looming or you have a more amiable/senior group than average. I'm not kidding when I say this. If you get a group of random C/C++ programmers together into a team and bring up one of these issues you're guaranteed to have a long, protracted, bloody argument on your hands. You'll have people arguing about which one is more productive, why one style is better than the other, how everything should be changed to use one of them, why the other style is bad, enforcing style guidelines, etc. And it'll go on, and on, and on.

It's not that people want anarchy -- most will agree on the benefits of consistency -- but the vehement arguments for choosing one style over another can be awe-inspiring.

Now, after hearing all of the arguments, you'll probably come out thinking that one style is indeed superior over the other, for various scientific-sounding reasons. Let me share a secret with you: they're all largely BS. The better and more experienced a programmer is, the more likely he'll be able to read and write a wide variety of styles. The mark of an inexperienced programmer is one who believes that he truly will not be able to write and maintain a working line of code unless the brace is positioned on line 7, column 17. The reason for preferring a particular style? Most likely just either (a) what he learned, or (b) what he's been using (or forced to use) in the past few years. That's basically it.

I won't claim to have transcended this phenomenon myself; I use the style that I do largely just because I learned C from K&R second edition. I have evolved it slightly over time, though.

Tab styles

Tabbing refers to indentation placed at the beginning of a line, where indentation is used to help indicate structure:

while video frames are left:
    fetch a video frame
    decode it
    for each video filter:
        run the video filter
    compress the video frame
    write it out to disk

There are two types of tabs. Hard tabs are ASCII code 09 and indent to the next tab stop, regardless of the number of character cells to the tab stop. Editors generally treat hard tabs as single characters for movement purposes, so that hitting right when you're in front of a tab moves you all the way to the tab stop. Soft tabs are tabs emulated using spaces -- the editor inserts as many spaces as are necessary to reach the tab stop.

I don't have a particular preference for either type of tab, and have coded in both styles without problems.

Hard tabs have the advantages that you can move across indentation faster if you use single-cell movement keys and have to fuss with them less often in order to line things up after an edit. They have the downsides that changing the tab size in the editor changes the arrangement of all of the code, and you have less flexibility in lining things up since you can only indent to tab stops. Hard tabs also have the dubious advantage of working when you are using a proportional font -- but that is a practice that is best avoided unless you are good at evading angry coworkers who found that your indentation only looks correct with the Wingdings 12 font and ClearType disabled.

Spacing done with soft tabs can be finely adjusted just by adding or removing spaces, which is nice. The code arrangement also won't turn into a mess if you happen to change the tab size. If you do a bunch of replaces in nicely lined up tables or initializer lists, though, you're likely to have to spend a lot of time fussing with the spacing again, and unlike hard tabs, the effect of hitting tab in the middle of indentation is a bit less predictable. When people aren't too careful about this, it's not unusual to see a few lines with indentation that's +/-1 off, which is a bit harder to notice than if you're off by an entire tab stop. But at least you don't have non-space characters hidden where you don't expect them.

You also have the choice of tab size. Common sizes are 2, 4, and 8, and occasionally you'll see really strange widths like 3. There aren't any good arguments for any of them, aside from 8 being the original tab size on old terminals, and that isn't a very good one. Generally the reason behind existing usage of a particular tab size is that someone has a habit of indenting way too much, too little, or just right for their editor width, or does/doesn't place a space before the parentheses in an if().

All in all, I don't have a real problem with either mode. VirtualDub is coded using hard tabs at width 4, but mainly just because that was the default in Visual C++ 4.0. I used to use 8 when I used BRIEF and Turbo C++ in DOS. What you definitely don't want is files that have a mix of both, as they're very unpleasant to edit. In Visual C++ 6.0, the useful Edit.WTFTabModeDidTheyUse command is bound to Ctrl+Shift+8 by default.

The one hard rule I have here is that C# code is always, always indented using spaces... but the reason for that is because I got burned by the Visual C# editor, which reformats code blocks automatically, and in certain scenarios, is lame enough to convert spaces to tabs in the middle of string literals and even single spaces into tabs.

Braces

Braces -- { and } -- are symbols used by languages similar to C to denote blocks of statements and initializers. Some languages, like Python, can look at indentation directly to determine the scope of a loop, but C/C++ use braces entirely for this purpose, with whitespace only being a convention for readability. There are several styles for brace placement. I won't bother to list all of them -- you can consult Wikipedia or the Jargon File for exhaustive lists -- but I will describe the two common ones I encounter. The first is same-line (often called K&R):

if (condition) {
    DoSomething();
}

...and the second is next-line (a.k.a. BSD or Allman):

if (condition)
{
    DoSomething();
}

Proponents of the first style say that the opening brace is best considered part of the control structure; those who like the second proclaim the benefits of matching brace position.

As you might have guessed, I use the first formulation. Well, most of the time. Write C++ long enough and you'll find that neither style works all of the time; for me, a slight mix of the two works better. For instance, I generally write functions like this:

void DoSomething() {
}

This doesn't work so well for class constructors, though, which I write in this manner:

MyClass::MyClass()
    : member1(0)
    , member2(0)
{
}

Why the goofy style, with the colon and comma at the beginning? It avoids having the oddball initializer at the end with no comma, which otherwise is a nice place to have source code control conflicts during integration, and also prevents disaster when people try to wrap conditionals with #ifdefs (which is a bad practice, but which is occasionally necessary).

I also like moving the brace to the next line when an if() condition gets a bit big:

if (condition1 &&
    condition2 &&
    condition3)
{
}

However, there are two disasters that I've found with this style. One is struct definition with initialization:

struct
{
    float f;
    int i;
}
fastConverter=
{
    val + 12582912.0f    // 2^22 + 2^23, the magic fast float-to-int value
};

...and the other is do...while() loops.

do
{
    ...
}
while(condition); // UGH

There's also the question of when to use and to omit braces. Omitting braces can be hazardous, especially when you see examples like this:

if (condition)
    // Handle special case
    DoSpecialCase();

On the other hand:

if (i < 0)
{
    i = 0;
}
else if (i > limit)
{
    i = limit;
}

...occupies too much space for my tastes, given its low complexity. The braces aren't any more worthwhile when put on the same line, either. For really simple statements, I'd just rather do this:

if (exit condition)
    break;

and save the strong layout for code that needs more mindshare. Makes the loops stand out more.

As you've noticed, most of the reasons for my brace preferences above are due to other stylistic choices I've made. None of them really stand well on their own.

Don't give in to style hate. Embrance multiwhitespaceism and be flexible to the situation at hand.

Comments

Comments posted:


Use a C beautifier to change the code to the way you want it and everyone is happy, no arguments.

anonymous - 22 04 06 - 03:52


Well, not quite. I'll agree that a code beautifier could save a lot of time in fixing badly formatted code, but you wouldn't want to use one regularly in team development with different settings because it would probably make irreversible changes to code that is not being worked on. Bad for maintenance and bad for source code control diffs. Perhaps modern beautifiers are better than I think, but I doubt that files would round-trip entirely cleanly between two different styles when it comes to issues like brace omission.

Phaeron - 22 04 06 - 04:09


While we are at it - what about pointer declaration?:
int *p
or
int* p

;*)

Murmel - 22 04 06 - 07:35


Beautifier is troublesome if you work with multiple developers in a repository.

For pointers, should be int *p, cos when you declare two pointers on the same line, it is

int *p
,*q;

Robin - 22 04 06 - 08:52


... declaring multiple variables on one line is another story.

Murmel - 22 04 06 - 09:05


int *p vs. int* p is an interesting one. The ANSI C language actually provides some guidance on this -- in the declaration, "int" is the specifier, and the * is part of the declarator that contains the name, so from a grammar standpoint, the * belongs with the variable. Many people prefer simply to never declare more than one variable per line, making the issue one purely of whitespace.

Occasionally people use (int * p) instead, but that makes you look wishy-washy.

For some reason, I use the inconsistent style of (int *) for pointers and (int&) for references. Don't remember where I picked this up -- probably got the reference style from the Getting Started book that came with Visual C++ 4.0.

What's really fun is when you get to complex types: (int *const *&). My rule is that you have to switch to typedefs when your types start looking like masked swearing.

Phaeron - 22 04 06 - 15:47


In my experience, using hard tabs with the tabstop set to anything but 8 is a disaster. I don't know about old ones, but all modern terminals (putty, xterm, etc.) use a tab stop of 8, so the code looks like a jagged mess when viewed with dumb Unix shell programs, pagers, etc. It's a win to have code look correct in email (pasted directly, CVS diff lists, etc). Viewing code in things like ViewCVS becomes a mess. Text editors (even Notepad) almost always default to 8.

This isn't religious--it's a real, practical problem with using any other hard tab stop: the only place the code will ever look correct is places explicitly configured to (and in programs with non-de-facto-standard default tab settings)--and in reconfiguring all of your programs to make them work with some oddball project, it breaks everything else. It's also very hard to fix large bodies of code that use a non-8 hard tab stop, if you care about code history in CVS/SVN or do nontrivial merging: reindenting the code for it tends to change every line of code.

Glenn Maynard - 22 04 06 - 20:01


I guess this comment system doesn't like dashes. :)

Glenn Maynard - 22 04 06 - 20:02


I guess my bent on things comes from having used source code control for most of my programming life. Do whatever makes the *diff* most readable! Which generally means use whatever the style of the code around where you are working is.

Kind of reminds me of the old joke flow chart, where the main logic highway goes
"did you f... with it?" -> "does anybody know?" -> "you poor bast...d!"

IanB - 22 04 06 - 22:04


> The reason for preferring a particular style? Most likely just
> either (a) what he learned, or (b) what he's been using (or
> forced to use) in the past few years. That's basically it.

I think a third option whould be added. When I was first faced with the issue I thought about it and arrived at an objective conclusion of what the best way is. I think a lot of people do it the same way.
In my case I concluded that the best way is to use tabs for indentation and spaces for alignment. This way it looks good no matter what tab sizes others on the team want to use. (I believe this style was later dubbed "smart indent" or somesuch.) I also concluded that it'd be incredibly stupid to mix tabs and spaces for indentation or to use tabs at all for alignment, because that'll look messed up if the tab size or the tab stop handling change.

Marcus Sundman - 23 04 06 - 18:00


> I think a lot of people do it the same way.

I mean that I think they also think about the issue and arrive at an objective conclusion (given their requirements). That is, they don't base their opinion on a feeling like you seem to think everybody does.

Marcus Sundman - 23 04 06 - 18:05


We have a coding standard at work, which specs all this stuff out. I hated it at first, because my code Looked Wrong. How dare they tell me how to write my code! Why, at uni, I could write just the way I wanted!

What I came to like about it was that I didn't have to think about, much less argue about, code layout anymore, and we could all just get on with writing code. The standard deals purely with code layout and naming, and has no rules like I've seen elsewhere such as 'you can't return early from a function'.

Another other good, pragmatic thing is the caveat that appears early on in our standard. It essentially says that if you follow the standard, and cannot get the compiler to generate the code you want, then the standard is broken, and must be changed. This hasn't happened yet.

mikel - 26 04 06 - 02:31


Maybe it is only me, but I found nothing wrong with the "two disasters" mentioned.

But what about other programmer practices (~ perversions)? :P

* space between if/while/for/switch and (

* return(...); or return ...; ?

* ?: as a left value

* definitions inside if, while, switch (example: switch(BYTE b = readbyte()) {...})

* exchanging integer values by xoring them three times (faster/slower? just lazier?)

* passing stucts to variable length arguments: printf("%d %d %d %d", rect)

* multiple function declarations having a common type (bool funct1(int t), funct2(float f), funct3(), ...;)

Gabest (link) - 26 04 06 - 07:33


Aw, darn. Apologies... my post was mangled.

Matt (link) - 27 04 06 - 15:07


The only practical use (in my experience) for "xor three times" is if you really need to swap without a third register, in which case you're probably using assembly and not C. Otherwise, it's just a gimmick. It's slow (data dependencies), hard for the compiler to optimize, and will blow up if you swap a value with itself. If you're in C++, just use swap() from .

(This is a bit off-topic--this isn't a religious or style issue, after all, but if it convinces someone not to do that, then I'll trust Avery to forgive me. :)

Glenn Maynard - 27 04 06 - 16:40


@Marcus:
I didn't say they were uninformed opinions, but nevertheless I believe they are often heavily weighted by personal experience, and less often backed up by actual readability/maintainability studies. This raises the problem that what is a common mistake for you is not necessarily common for everyone else. The book Code Complete, to its credit, does reference several formal studies.

There are also often hidden factors to such decisions. Does your editor expose a hard tab as an atomic step, or does it allow you to navigate the tabs as spaces, either by virtual space or silent conversion. These can influence your decision as well. Unfortunately, not everyone uses the same editor.

Do I believe that coding standards should be established solely from formal studies? Nope, circumstances vary too much. I do believe, though, that care has to be taken to determine what really needs to be in a standard and what is unnecessary imposition of preference.

@Gabest:
Space between keyword and (: I do so for if(), but not for while(), for(), and function calls. Shrug. Probably learned to do so because with 4-tabs, space in if() makes the comparison and assignment line up.
Parens with return: I don't, but it is a bit of an anomaly in the language. Strangely enough, I often do add them for sizeof().
?: as lvalue: Don't usually find an occasion for this, and I doubt it's different from an if() in modern compilers. Looks like Perl.
Definitions inside if/while/switch: Have been known to do it, but shying away from it now because VC++ can ICE if destructors are involved. Depends on how lazy I am. Amusing to use since other people swear at you when they find it.
Structs to varargs function expecting scalars: Invokes undefined behavior (and can actually break on some compilers).
Exchanging by xoring: Too much typing. std::swap(x,y) is shorter.
Multiple function declarations: Nope, usually falls under not doing more than one decl per line in general.

@Glenn Maynard:
Yes, in most cases it will be slower. On an OOO chip, the move formulation can sometimes be optimized out entirely by the register renamer in the front end, instead of requiring execution units. It can also sometimes be eliminated by renaming registers in manually in software. Three XORs might actually be faster in MMX/SSE on a pre-Prescott P4 due to the long move latency, but there are still usually better ways. In fact, I'm hard pressed to think where it's a good idea to use... 68K's EXG is twice as fast, and most older CPUs require the accumulator to be the destination.

Still, it's a neat trick, and if you have additional registers, variants of it can be used to swap subsets of bits between registers, which is more useful.

Phaeron - 28 04 06 - 03:30

Comment form


Please keep comments on-topic for this entry. If you have unrelated comments about VirtualDub, the forum is a better place to post them.
Name:  
Remember personal info?

Email (Optional):
Your email address is only revealed to the blog owner and is not shown to the public.
URL (Optional):
Comment: /

An authentication dialog may appear when you click Post Comment. Simply type in "post" as the user and "now" as the password. I have had to do this to stop automated comment spam.



Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.