This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Should a function have only one return statement?
Hello,
gcc 4.4.4 c89
Is it good programming practice to return from 1 point in a function.
I have written a function below. However, I am returning from 2 possible points.
Is this good style?
static int init_data(struct timeout_data_t *timeout_data)
{
if(timeout_data == NULL) {
fprintf(stderr, " [ %s ] [ %d ]\n",
__func__, __LINE__);
return FALSE;
}
/* Assign data */
timeout_data->seconds = 3;
timeout_data->func_ptr = timeout_cb;
return TRUE;
}
If it aids readability, then there is nothing wrong with it.
Personally, I write this kind of code all of the time.
This is an ongoing religious-style debate without an accepted answer. There are many people on both sides of the argument, who feel strongly about it.
I don't think there's anything wrong with it personally, but the best approach is to go with the style guidelines of your team, if they have some (and if not, just ask about it. If anyone recoils in horror, it would be kinder to stick to single-return-point).
I've had managers that lived and died by the 1 return policy for the sake of "readability", even though it's much more readable in some cases without it.
The bottom line is... if the man that signs your paycheck says you're only going to use 1 return, use 1 return. The best way to do this is
type myfunc(params) {
type result = defaultValue;
// actual function here, word for word
// replace "return $1" with "result = $1"
return result;
}
This is a valid way to do things in their book, and will smile at your 1 return policy adherence. Of course, you know using this adds ZERO readability because all you've done is replace "return" (which is syntax highlighted) with "result =" which is not. But you've made your boss happy, which when you break it all down is what development is about anyway, right? :-)
In straight C, I think that error checking/parameter verification at the top of the function with a return (or possibly even multiple return points in the parameter verification) results in reasonably clean code. After that point, though, my opinion is that it is a good idea to have one single return at the bottom of the function. That helps avoid problems with cleanup (e.g., freeing of memory) that might be allocated in the workings of the function.
There's nothing inherently wrong about having more than one exit point, especially when you're returning on errors. Returning immediately usually makes for clearer code than having the whole thing wrapped in an if/else statement and setting some result flag to be returned at the end. (When you see "return result;", you have to look through all of the earlier code to see how and when result gets set. More moving parts == less clarity.)
You've tagged your questions as "C" which makes a difference.
In C you might write code such as
open file
process data
close file
If you put a return in the middle of the process data section then you're likely to skip the essential cleanup so it might be considered bad practice to have multiple return points because it's very easy to mess up.
If it was C++ then its best practice to let destructors handle cleanup so it's not nearly such a potential problem so this advice is somewhat obsolete in c++
As Oded and Andrzej Doyle pointed out there is nothing wrong with it.
They is no such thing as a golden rule when it comes to this.
The first an most important thing you have to keep in mind when writing code is that some one else will have to read it and make sense out of it. Maybe you will have to go about it in a couple of months, and if you have made a mess you will regret it.
Personally I always:
if the code is new used the coding style everybody else is using in the project.
If editing others code used the coding style already implemented there.
Avoid above all code optimizations (the compiler is best at that).
keep it clean and lean.
If your function is small enough (10-15 lines), as it should be :), then it really doesn't matter if you use a single return point or multiple one. Both are equally readable.
Problems start cropping up with badly designed large functions. In such cases both the styles, returning from a single point, and returning from multiple points, further complicates the function, although even in such cases I prefer returning early and returning at multiple points.
It's often the case that you have to check for several conditions etc before you start with the real work, and then you are tempted to do an early return, as in your code. I think this is fine for short methods, but when it gets more complicated I'd suggest to break your code in a "setup and check" method and a "real work" method, both having only one exit. Of course as long as it's readeable, it's fine to have multiple returns (e.g. in a long switch statement).
Failing (and thus returning) early is a very very very good practice. All the code after the checks is free of a lot of potential errors.
Related
I've recently been taking a C course as part of a university degree. We have been forbidden from using goto, break and continue, and must only use a single return statement from a function.
I have been writing C for many years as a hobby without these restrictions and have been struggling to write in the style they require - often ending up with mountains of nested if statements. I try to avoid goto where possible, but have a habit of using break, continue and multiple return statements very liberally and have never had any issues.
Why are these features considered bad practice?
This is highly subjective, as all 4 of those things have trade-offs--pros and cons.
Ask your teacher, and report back here.
goto has an unnecessarily bad reputation. People fear it waaay more than they should! I think it is because using goto can be easily abused, especially if you jump outside your function, or jump backwards (upwards in the code). If you jump only downwards, however, and within the same function, not crossing over variable declarations in the process, goto can be an excellent technique to help you achieve a clean single return statement at the end of a function. In C, it can be the perfect way to handle errors in complex initializations! See my usage in my answer here: Opaque C structs: various ways to declare them. See also the Additional reading and justification for valid usage of goto in error handling for professional code section at the bottom of my answer there.
In some organizations, including some safety-critical embedded microcontroller applications I have worked in in the self-driving car industry, using goto can even be required. I've worked in code bases where the above error handling technique with a single return and using goto was required by my organization's coding guidelines. It's not automatically evil. Rather, it's a tradeoff with pros and cons. Unfortunately, many people I've worked with also have an unfounded revulsion towards goto which was probably planted by their teacher, like your teacher for instance. This revulsion can lead to some pretty awful code at times when goto would have beautified and simplified it tremendously.
Note also that in C++ there are other ways to do error handling that aren't as accessible in C, but still, goto could be used.
break and continue are much less-easily abused. Perhaps the only real argument against them is code clarity.
Ex: do something 10 times:
// fine, but perhaps not as clear
const int NUM_TIMES = 10;
int i = 0;
while (true)
{
printf("i = %i\n", i);
i++;
if (i >= NUM_TIMES)
{
break;
}
}
// clearer (withOUT `break`)
int i = 0;
while (i < NUM_TIMES)
{
printf("i = %i\n", i);
i++
}
// or
for (int i = 0; i < NUM_TIMES; i++)
{
printf("i = %i\n", i);
}
// The above example is trivial, but imagine you are NOT just
// incrementing a number! The non-`break` while loop with your
// condition up-front can be clearer. The `break` option is just
// fine too, but it's a matter of taste.
A single return statement is best achieved when using goto. Otherwise, it requires tons of nesting. So, that is contrary to your teacher's guidance, it seems.
Many people, however, opt for multiple return statements to exit a function early and avoid tons of nested braces. It's basically a tradeoff of:
tons of nesting, OR
goto, and a single return, OR
multiple returns
In languages like C, I use goto and a single return, unless my stinking peers won't approve it, and they fight with me, in which case I conform to whoever is reviewing me so I can get my stinking code merged. :) (Replace "stinking" with "beloved", for your peers, of course).
In languages like C++, where developers hate goto even more than in C, I generally use multiple returns or extra nesting and breaking the code out into sub-functions--again, to appease my peers who don't know and love C.
In Python, where goto does not exist, I use multiple returns.
At the end of the day, ask your teacher. Take mental notes. Learn why they are doing it. Learn from us. Learn from books. Form your own opinions. Begin recognizing trends and "best practices", and form your own opinions. If you need to do what your teacher wants, even if they're wrong, for the grade, do it. But do it the "better" way you determine outside that class.
In code reviews, if your stinking peer won't approve your beautiful goto usage, try to convince them. If you can't, make the change to avoid goto, reduce friction, and move on. It's not worth fighting about. Everything is a tradeoff. There are many "right" ways to do things.
Note to all: I say "stinking" in jest. I am very grateful for the job that I have.
TODO (Notes to self):
Try forcing goto to jump outside the function, even if it produces undefined behavior, as a demo to prove it is dumb:
goto jump outside function
https://stackoverflow.com/a/44843514/4561887
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I was once told that functions with one input and one output(not exactly one) should not print messages when being called. But I don't understand. Is it for security or just for convention?
Let me give an example. How to deal with an attempt that access data in a sequential list with an incorrect index?
// 1. Give out the error message inside the function directly.
DataType GetData(seqList *L, int index)
{
if (index < 0 || index >= L->length) {
printf("Error: Access beyond bounds of list.\n");
// exit(EXIT_FAILURE);
}
return L->data[index];
}
// 2. Return a value or use a global variable(like errno) that
// indicates whether the function performs successfully.
StateType GetData(seqList *L, int index, int *data)
{
if (index < 0 || index >= L->length) {
return ERROR;
}
*data = L->data[index];
return OK;
}
I think there are two things going on here:
Any visible and unexpected side-effect such as writing to streams is generally bad, and not just for functions with one input and one output. If I was using a list library, and it started silently writing error messages to the same output stream I was using for my regular output, I'd consider that a problem. However, if you are writing such a function for your own personal use, and you know ahead of time that the action you want taken is always to print a message and exit(), then it's fine. Just don't force this behavior on everyone else.
This is a specific case of the general problem of how to inform callers about errors. A lot of the time, a function cannot know the correct response to an error, because it doesn't have the context that the caller does. Take malloc(), for instance. The vast majority of the time, when malloc() fails, I just want to terminate, but once in a great while I might want to deliberately fill the memory by calling malloc() until it fails, and then proceed to do something else. In this case, I don't want the function to decide whether or not to terminate - I just want it to tell me it's failed, and then pass control back to me.
There are a number of different approaches to handling errors in library functions:
Terminate - fine if you're writing a program yourself, but bad for a general purpose library function. In general, for a library function, you'll want to let the caller decide what to do in the case of an error, so the function's role is limited to informing the caller of the error.
Return an error value - sometimes OK, but sometimes there is no feasible error value. atoi() is a good case in point - all the possible values it returns could be correct translations of the input string. It doesn't matter what you return on error, be it 0, -1 or anything else, there is no way to distinguish an error from a valid result, which is precisely why you get undefined behavior if it encounters one. It's also semantically questionable from a slightly purist point of view - for instance, a function which returns the square root of a number is one thing, but a function which sometimes returns the square root of a number, but which sometimes returns an error code rather than a square root is another thing. You can lose the self-documenting simplicity of a function when return values serve two completely separate purposes.
Leave the program in an error state, such as setting errno. You still have the fundamental problem that if there is no feasible return value, the function still can't tell you that an error has occurred. You could set errno to 0 in advance and check it afterwards every time, but this is a lot of work, and may just not be feasible when you start involving concurrency.
Call an error handling function - this basically just passes the buck, since the error function then also has to address the issues above, but at least you could provide your own. Also, as R. notes in the comments below, other than in very simple cases like "always terminate on any error" it can be asking too much of a single global error handling function to be able to sensibly handle any error that might arise in a way that your program can them resume normal execution. Having numerous error handling functions and passing the appropriate ones individually to each library function is technically possible, but hardly an optimal solution. Using error handling functions in this way can also be difficult or even impossible to use correctly in the presence of concurrency.
Pass in an argument that gets modified by the function if it encounters an error. Technically feasible, but it's not really desirable to add an additional parameter for this purpose to every library function ever written.
Throw an exception - your language has to support them to do this, and they come along with all kinds of associated difficulties including unclear structure and program flow, more complex code, and the like. Some people - I'm not one of them - consider exceptions to be the moral equivalent of longjmp().
All the possible ways have their drawbacks and advantages, as of yet humanity has not discovered the perfect way of reporting errors from library functions.
In general you should make sure you have a consistent and coherent error handling strategy, which means considering whether you want to pass an error up to a higher level or handle it at the level it initially occurs. This decision has nothing to do with how many inputs and outputs a function has.
In a deeply embedded system where a memory allocation failure occurs at a critical juncture, for example, there's no point passing that error back up (and indeed you may well not be able to) - all you can do might be enter a tight loop to let the watchdog reset you. In this case there's no point reserving invalid return values to indicate error, or indeed in even checking the return value at all if it doesn't make sense to do so. (Note I am not advocating just lazily not bothering to check return values, that is a different matter entirely).
On the other hand, in a lovely beautiful GUI app you probably want to fail as gracefully as possible and pass the error up to a level where it can be either worked around / retried / whatever is appropriate; or presented to the user as an error if nothing else can be done.
It is better to use perror() to display error messages rather than using printf()
Syntax:
void perror(const char *s);
Also error messages are supposed to be sent to the stderr stream than stdout.
Yes, it's a bad practice; even worse is that you're sending the output to stdout rather than stderr. This could end up corrupting data by mixing error message in with output.
Personally, I believe very strongly that this kind of "error handling" is harmful. There is no way you can validate that the caller passed a valid value for L, so checking the validity of index is inconsistent. The documented interface contract for the function should simply be that L must be a valid pointer to an object of the correct type, and index a valid index (in whatever sense is meaningful to your code). If an invalid value for L or index is passed, this is a bug in your code, not a legitimate error that can occur at runtime. If you need help debugging it, the assert macro from assert.h is probably a good idea; it makes it easy to turn off the check when you no longer need it.
One possible exception to the above principle would be the case where the value of L is coming from other data structures in your program, but index is coming from some external input that's not under your control. You could then perform an external validation step before calling this function, but if you always need the validation, it makes sense to integrate it like you're doing. However, in that case you need to have a way to report the failure to the caller, rather than printing a useless and harmful message to stdout. So you need to either reserve one possible return value as an error sentinel, or have an extra argument that allows you to return both a result and an error status to the caller.
Return a reserved value that's invalid for a success condition. For example, NULL.
It is advisable not to print because:
It doesn't help the calling code reason about the error.
You're writing to a stream that might be used by higher level code for something else.
The error may be recoverable higher, so you might be just printing misleading error messages.
As others have said, consistency in how you deal with error conditions is also an important factor. But consider this:
If your code is used as a component of another application, one that does not follow your printing convention, then by printing you're not allowing the client code to remain faithful to its own strategy. Thus, using this strategy you impose your convention to all related code.
On the other hand, if you follow the "cleaner" solution of returning a reserved value and the client code wants to follow the printing convention, the client code can easily adapt to what you return and even print an error, by making simple wrappers around your functions. Thus, using this strategy you give the users of your code enough space to choose the strategy that best works for them and to be faithful to it.
It is always best if code deals with one thing only. It is easier to understand, it is easier to use, and is applicable in more instances.
Your GetData function that prints an error message isn't suitable for use in cases where there may not be a value. i.e. The calling code wants to try to get a value and handle the error by using a default if it doesn't exist.
Since GetData doesn't know the context it can't report a good error message. As an example higher up the call stack we can report hey you forgot to give this user an age, vs in GetData where all it knows is we couldn't get some value.
What about a multithreaded situation? GetData seems like it would be something that might get called from multiple threads. With a random bit of IO shoved in the middle it will cause contention over who has access to the console if all the threads need to write at the same time.
This is a super simple example, in C here, to illustrate a subtle error that I don't know how to expose as a bug through a test.
Consider:
#include <stdio.h>
int main()
{
int a;
int b;
int input;
printf("Enter 1 or 2: ");
scanf("%d", &input);
switch(input) {
case 1:
a = 10;
/* ERROR HERE, I FORGOT A BREAK! */
case 2:
b = 20;
break;
default:
printf("You didn't listen!\n");
return 1;
break;
}
if(input == 1) {
b = 30;
printf("%d, %d\n", a, b);
} else {
printf("%d\n",b);
}
return 0;
}
As noted in the code, a break is missing so when 1 is entered, it falls through to case 2. The output for 1 though doesn't reflect this as it overwrites b later. So all tests that we can design, say by entering a number from the set {1, 2, 10} all result in the correct output.
In reality, the assignments inside the switch could be very expensive and so this bug could be quite costly. But, assuming it was written this way from day one, there's no benchmark to see that the cost is higher than expected.
So what can be done to flush out these kinds of errors? Is there a way to design test cases to expose it in production software?
EDIT
So I guess I wasn't entirely clear -- I wrote it in C to illustrate the type of problem encountered, but in reality it's not specific to C. The point I'm trying to make is that the code goes into sections we never intended it to go into (in this case because of a forgotten break to illustrate the point). My actual case is a Fortran code with 700,000 lines and it is going into branches we never intended it to go into because of poor if/switch design that is legal from a language point of view but potentially very expensive.
Is it possible to design a test or look at some data from some tool that will tell us it's going into branches it shouldn't be? I caught a mistake by printing "I shouldn't be here!" inside all the cases and saw that it was printed, there's gotta be a better way than randomly seeing it and putting print statements.
You can define coding convention for switch statements, so that each branch will impose a special state. Like a variable getting assigned the very case`s value. For example:
switch (v) {
case 1:
vcheck = 1;
...
break;
case 2:
vcheck = 2;
...
break;
}
And test vcheck in your test case.
Other than that you can use tools that perform static code analysis of validation of MISRA rules - and engage them into your build process. They will induce some piece of mind... :-)
Finally, (my favorite) you can write a script that checks for such cases and warns agains them.
The correct state for case 1 is that b won't be set.
Check to see if b is set.
You may need to break your code down into smaller segments to test this if you're setting b later, but that's just good modularity.
It seems like you're asking "how do I test untestable code?". The answer is that it takes skill and planning to write testable code, it can't just be an afterthought.
There's tons of stuff on the web to help you write testable code:
https://www.google.com/search?q=writing+testable+code
For your specific example, it is in no way a mistake / bug by definition. The possibility to fallthrough is wanted in the language. If you want to forbid certain dangerous language features, then linters are the way to go.
To avoid completely unforeseen mistakes, there is the one rule: Always code defensively and make use of asserts whereever you can put them.
Why is this a bug I ask? Using any kind of black-box testing the code works. So, if the only requirement is that the code works, then there is no bug.
But the code is flawed. That missing break makes the code more difficult to understand and harder to maintain.
Coding conventions are rules on how the code should look. Adherence to coding conventions can not be done by testing the compiled program, they must be done on the source code.
Testing coding conventions is done through code inspection (automatic or manual).
Edit:
If you are worried about performance, then use instrumentation tools to find the "hot spots". You will find that most of the execution time is probably spent in just a few modules. Review those modules and every call to them. You will find that you only need to review 10-30 000 lines of code. Since the review scope is limited, the review should take 1-3 weeks.
Bottom line: Code review is vastly superior to testing when it comes to finding subtle bugs.
If input==1 and you see b = 30 on the output, you know something is wrong. Also, remember in the else clause, you should write something to b before reading from it. In the case of default:, (say, input==100) you might end up reading from a location without properly setting it.
Besides, code reviews, if you can afford them should help greatly in finding things like these.
I am just wondering would it be better to do this:
if((fd = open(filename, O_RDWR)) == -1)
{
fprintf(stderr, "open [ %s ]\n", strerror(errno));
return 1;
}
or this
fd = open(filename, O_RDWR);
if(fd == -1)
{
fprintf(stderr, "open [ %s ]\n", strerror(errno));
return 1;
}
Many thanks for any suggestions,
Yuck, split it up. What do you gain by mashing it all on one line? Let's compare and contrast:
Single-line:
Advantages:
Disadvantages: Hard to read, prone to error. (Consider your first revision.)
Multi-line:
Advantages: Easy to read, less error-prone.
Disadvantages:
I think it's clear. :)
"Sometimes putting it on one line makes more sense, for example: while ((c=getchar())!=EOF)"
That's fine, but that isn't the case here. There are times when not splitting it up makes more sense, but in general, don't.
"It saves more vertical space"
If one line is killing your ability to see the function, you need to 1) buy a monitor with a resolution higher than 640x480, and 2) Write smaller functions.
Really, I've never understood that argument for anything, functions should easily fit on any screen, regardless of a one-line difference.
"Multiple lines make it look complex"
Not really, shoving it on one line is arguably harder to read and more complex looking. Splitting things up makes it simpler to process one bit at a time, one shouldn't assume two lines makes it twice as complex.
Several people have argued in favor of the second. I disagree with them. While there was (apparently) initially a minor issue with = vs. == in the first one, I'd argue that it IS a minor issue.
A much bigger issue is that it's all too common for people (especially if they're in a hurry) to skip over the error checking -- leaving out the if (whatever == -1) completely, usually on the theory that what they're working on is quick, throwaway code and checking for the error isn't really needed. This is a really bad habit; I can practically guarantee that every person reading this has seen real code that skipped error checking like this, even though it really, really should have had it.
In code like this, attempting to open the file and checking for an error in having done so should be inextricably bound together. Putting the two into the same statement reflects the proper intent. Separating the two is just plain wrong -- they should not be separated in any way at any time for any reason. This should be coded as a single operation because it should be a single operation. It should always be thought of and coded as a single operation.
The excuses for doing otherwise are, in my opinion, quite weak. The reality is that anybody who uses C needs to be able to read code that combines an assignment with a conditional test. Just for an obvious example, a loop like while ((ch=getchar()) != EOF) pretty much needs to be written as a combined assignment and test -- attempting to test for EOF separately usually leads to code that just doesn't work correctly, and if you do make it work correctly, the code is substantially more complex.
Likewise, with the problem of - vs. ==. Since I didn't see the defect to start with, I'm not sure how much separating the two would have done to avoid problems, but my immediate guess is that it probably made almost no difference at all. Compilers that will warn you when what was supposed to be a condition contains only an assignment have been around for years (e.g. gcc). In most cases, the symptoms are almost immediately obvious anyway -- in short, the fact that you made a particular typo in one part of this posting but not the other doesn't prove (or honestly even indicate) much of anything about the relative difficulty of the two.
Based on that kind of evidence, I'd apparently believe that "not" is harder to type than "immediately", since I just typed "immediately" without a problem, but had to correct "not" (twice, no less) before it came out right in the previous sentence. I'm pretty sure if we went by how often I mistype it, "the" is the single most difficult word in the English language.
Maybe something where the parentheses make the ordering obvious?
if((fd = open(filename, O_RDWR)) == -1)
In this example, I'll join the chorus saying the second method is better.
The tougher case is when it's in a loop, like:
while ((c=getchar())!=-1)
{
... do something ...
}
versus
while (true)
{
c=getchar();
if (c==-1)
break;
... do something ...
}
In cases like that I prefer to do it on one line because then it makes clear what is controlling the loop, which I think overrides the drawbacks of the complex combination of assignment and testing.
Its a style thing - you're not asking a precedence (not presidence).
Many people will argue the latter example is clearer.
The second is better for readability's sake, but I know I do the first too often. The = operator will take precedence, especially since you have it in quotes, allowing the assigned value to be returned & compared by the == operator.
Except for standard idioms -- ones that are so common that everyone immediately gets what you are trying to do -- I would avoid doing the assignment in the conditional. First, it's more difficult to read. Second, you leave yourself open (at least in weakly typed languages that interpret zero as false and non-zero as true) to creating bugs by using an errant assignment operator in the conditional check.
This is a matter of style and is subjective. They do the same thing. I tend to prefer the later because I find it easier to read, and easier to set breakpoints/examine variables in the debugger.
(-1 == __whatever__)
to minimize typo
The first case is very normal when you're writing an input loop, because the alternative is to have to write the input command twice -- once right before the loop, and once right at the end of the loop.
while ( (ch=getchar()) != -1){
//do something with it
}
I think that the second way is more normal for an if statement, where you don't have the same concern.
What advantage, if any, is provided by formatting C code as follows:
while(lock_file(lockdir)==0)
{
count++;
if(count==20)
{
fprintf(stderr,"Can't lock dir %s\n",lockdir);
exit(1);
}
sleep(3);
}
if(rmdir(serverdir)!=0)
{
switch(errno)
{
case EEXIST:
fprintf(stderr,"Server dir %s not empty\n",serverdir);
break;
default:
fprintf(stderr,"Can't delete dir %s\n",serverdir);
}
exit(1);
}
unlock_file(lockdir);
versus something more typical such as
while(lock_file(lockdir)==0) {
count++;
if(count==20) {
fprintf(stderr,"Can't lock dir %s\n",lockdir);
exit(1);
}
sleep(3);
}
if(rmdir(serverdir)!=0) {
switch(errno) {
case EEXIST:
fprintf(stderr,"Server dir %s not empty\n",serverdir);
break;
default:
fprintf(stderr,"Can't delete dir %s\n",serverdir);
}
exit(1);
}
unlock_file(lockdir);
I just find the top version difficult to read and to get the indenting level correct for statements outside of a long block, especially for longs blocks containing several nested blocks.
Only advantage I can see is just to be different and leave your fingerprints on code that you've written.
I notice vim formatting would have to be hand-rolled to handle the top case.
The top example is know as "Whitesmiths style". Wikipedia's entry on Indent Styles explains several styles along with their advantages and disadvantages.
The indentation you're seeing is Whitesmiths style. It's described in the first edition of Code Complete as "begin-end Block Boundaries". The basic argument for this style is that in languages like C (and Pascal) an if governs either a single statement or a block. Thus the whole block, not just its contents should be shown subordinate to the if-statement by being indented consistently.
XXXXXXXXXXXXXXX if (test)
XXXXXXXXXXXX one_thing();
XXXXXXXXXXXXXXX if (test)
X {
XXXXX one_thing();
XXXXX another_thing();
X }
Back when I first read this book (in the 90s) I found the argument for "begin-end Block Boundaries" to be convincing, though I didn't like it much when I put it into practice (in Pascal). I like it even less in C and find it confusing to read. I end up using what Steve McConnel calls "Emulating Pure Blocks" (Sun's Java Style, which is almost K&R).
XXXXXXXXXXXXXX X if (test) {
XXXXXX one_thing();
XXXXXX another_thing();
X }
This is the most common style used to program in Java (which is what I do all day). It's also most similar to my previous language which was a "pure block" language, requiring no "emulation". There are no single-statement bodies, blocks are inherent in the control structure syntax.
IF test THEN
oneThing;
anotherThing
END
Nothing. Indentation and other coding standards are a matter of preference.
Personal Preference I would have thought? I guess it has the code block in one vertical line so possibly easier to work out at a glance? Personally I prefer the brace to start directly under the previous line
It looks pretty standard to me. The only personal change I'd make is aligning the curly-braces with the start of the previous line, rather than the start of the next line, but that's just a personal choice.
Anyway, the style of formatting you're looking at there is a standard one for C and C++, and is used because it makes the code easier to read, and in particular by looking at the level of indentation you can tell where you are with nested loops, conditionals, etc. E.g.:
if (x == 0)
{
if (y == 2)
{
if (z == 3)
{
do_something (x);
}
}
}
OK in that example it's pretty easy to see what's happening, but if you put a lot of code inside those if statements, it can sometimes be hard to tell where you are without consistent indentation.
In your example, have a look at the position of the exit(1) statement -- if it weren't indented like that, it would be hard to tell where this was. As it is, you can tell it's at the end of that big if statement.
Code formatting is personal taste. As long as it is easy to read, it would pay for maintenance!
By following some formatting and commenting standards, first of all you show your respect to other people that will read and edit code written by you. If you don't accept rules and write somehow esoteric code the most probable result is that you will not be able communicate with other people (programmers) effectively. Code format is personal choice if software is written only by you and for you and nobody is expected to read it, but how many modern software is written only by one person ?
The "advantage" of Whitesmiths style (as the top one in your example is called) is that it mirrors the actual logical structure of the code:
indent if there is a logical dependency
place corresponding brackets on the same column so they are easy to find
opening and closing of a context (which may open/close a stack frame etc) are visible, not hidden
So, less if/else errors, loops gone wrong, and catches at the wrong level, and overall logical consistency.
But as benefactual wrote: within certain rational limits, formatting is a matter of personal preference.
Its just another style--people code how they like to code, and that is one accepted style (though not my preferred). I don't think it has much of a disadvantage or advantage over the more common style in which brackets are not indented but the code within them is. Perhaps one could justify it by saying that it more clearly delimits code blocks.
In order for this format to have "advantage", we really need some equivalent C code in another format to compare to!
Where I work, this indentation scheme is used in order to facilitate a home-grown folding editor mechanism.
Thus, I see nothing fundamentally wrong with this format - within certain rational limits, formatting is a matter of personal preference.