- Feature Articles
- CodeSOD
-
Error'd
- Most Recent Articles
- Secret Horror
- Not Impossible
- Monkeys
- Killing Time
- Hypersensitive
- Infallabella
- Doubled Daniel
- It Figures
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
goto is bad in all but extreme circumstances, I agree, but break and continue can be aid clarity when used correctly, and the use documented.
For example, say I want to loop through a file one character at a time, do something to every chacter, but then only do the majority of the loop body if a condition is met:
If you're using 8-char tabs, as above, the loop body ends up halfway across the screen, and there's an extra set of braces that doesn't fit in the logic. this is much clearer, IMO:
Admin
Admin
What's up with people claiming that a state machine is the wrong solution here? It's the cleanest and simplest way to solve the problem. It's also the most efficient. What more do you want?
As for the <font face="Courier New">goto</font>s... well, it's a very short function, and after somebody finds the <font face="Courier New">strtol()</font> bug, the only time it'll ever have to be touched again will be to convert to <font face="Courier New">TCHAR</font> or Unicode, which won't affect the algorithm at all. It looks scary because it's an unfamiliar idiom, that's all. You could argue for a <font face="Courier New">switch</font> thing instead, and because that's a more popular idiom it'll be more maintainable. The <font face="Courier New">switch</font> would be wasteful, but not to a degree that's usually an issue.
There are cases where a function has to be made as efficient as humanly possible, even at some cost in readability (Moore's Law stopped applying to clock speeds two years ago, kids). In such a case this would be the Right Thing, except for that call to <font face="Courier New">strtol()</font>. If speed is really a problem, that call ought to be replaced with code that converts the hex "by hand" as another commenter suggested above.
The question is whether this optimization is premature or appropriate, and you'd really have to have seen what the profiler said before you can make that call.
The <font face="Courier New">strtol()</font> bug is a valid and serious problem. The "accept" label should (as noted above) not be called "accept", because it isn't. The eight-bit char thing is a valid WTF in this day and age; it's odd that nobody mentioned that. The objection to <font face="Courier New">goto</font> in principle is infantile. There are places (not many, but some) where it makes sense. Being a competent programmer means recognizing those places. You know, thinking -- not just robotically quacking a context-free homily some ideologue poured down your throat in CS101. God won't strike you dead if your code isn't always properly Object Oriented. OOP is a valuable tool, not an end in itself.
Admin
Minor point: C does not define 0 (zero) to be the equivalent of false. Almost all implementations of the language do make this assumption but there are a few that don't. Technically, therefore, the "!size" construct makes an inherently false assumption. C++ on the other hand does define False to be numerically zero. We used to get around the C assumption by using defines:
#define TRUE (1==1)
#define FALSE (1==0)
But that was long ago...
The overriding point about the construct for either language is that "(size == 0)" is easier for the brain to automatically digest than "(!size)".
Admin
Bustaz Kool: The comparison operators in C have always been defined as yielding an int with a value of 0 for false or 1 for true. Maybe you had to deal with broken compilers, but today those macros would be a WTF in themselves.
Admin
"Minor point: C does not define 0 (zero) to be the equivalent of false."
I'm not sure what planet you got your spec from, but ISO C99 is pretty clear that integer zero and logical false are interchangeable. For examples, see 6.5.3.3 paragraph 5 and 6.8.4.1 paragraph 2. Are you confusing this with the issue where null pointers may have non-zero bits? (Note that "(!nullpointer)" must still evaluate to true for any null pointer, but you cannot portably rely on memset(&ptr, 0, sizeof(ptr)) to make ptr a null pointer.)
The overriding point about the construct for either language is that VB (or Pascal) programmers should stick to VB (or Pascal) and not attempt to make other languages look like VB (or Pascal). I have known people to #define begin { and #define end ;}, but that does not make it idiomatic C.
If that was an attempt at humor, perhaps you should trade your sense of humor in for a new one.
Admin
Why are you being so mean to me?
Admin
As others have noted, C++ does in fact have a native boolean type. "true" and "false" are even keywords. No, it's no. And don't turn to the C++ Standard as a defense. It only reports on what will compile. Not on what are good programming practices.
Remember, our goal here is not merely to write code that will compile, but code that other people can read & understand -- preferable without having to think too much about it.
So, if you were to take an int an use it as a boolean:
int MyFlag = TRUE;
Then I would have no problem using a !:
if (!MyFlag)
However, if you are going to use an int as a number, then you should use operators that relate too it as a number:
int MyCounter = 15;
if (MyCounter == 0)
Admin
But he said nothing about your not aligning the opening & closing braces?
So, he'd want you to write (using a real example)
for(int i = 0; i < somecount; i++)
{
if(a[i] == target)
break;
}
return i;
as :
int foundit;
for(int i = 0; i < somecount; i++)
{
if(a[i] == target)
{
foundit = i;
i = somecount;
}
}
return foundit;
Ick!
IckIckIckIckIck!!!
So, let's see.... It's Ugly, Confusing, and requries the processor to do more work. It's a three time loser!
Admin
I think this site could open special corner dedicated to code/solutions written by consultants. I don't want to blame all academy folks, but experience in software production is quite rare knowledge among them. Usually they have pompous titles and prefixes on their business card, but little understanding what the real problems of software development are. It's because computer sciences and software development are two different things (however, with some common basis). Unfortunately, many managers think that CS degree automatically bestows SW development skills and experience. They mistaken bitterly.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p>
Any SW developer (with degree or without one) who touched real code just once knows that there are no silver bullets and universal rules. There is no such thing in real life as "if you'll use goto consider yourself fired". There are problems thatrequire reasonable, maintainable and comprehensible solutions.
Admin
There are no all embracing universal rules like that. The C++ language contains these keywords and there are situations when you'll use them. If you don't believe me, then take any big C++ library and grep for break/goto/continue.
Admin
jamescurran, you're on hop about the counters.
Treating a counter as a boolean is absolutely canonical C/C++ idiom and has been so since the 1970s. Any competent programmer knows what it means and recognizes it instantly. If it weren't so pervasive, I'd agree with you, but it is, so don't worry about it.
And just by the way, more people should do the constant-on-the-left thing. Like so:
if ( 0 == counter ) { ... }
That's so if you should happen to mistype the operator, the compiler will tell you. It's a good habit. Won't save you if you're comparing two valid lvalues, of course.
Admin
I do see a certain point in disallowing break from loops, though it's not a general rule. Often, break can simplify the code, but it can also be confusing, especially when the loop body grows large.
As for the above Code, That would be best written as
for(int i = 0; i < somecount && a[i] != target; ++i);
return i;
Admin
Doh! Typical comment... Apparently (code) readability and maintenance are not in your vocabulary... Too bad... :-(
W.
Admin
Ya'know... I used to feel exactly the same way --- for the first 3 or 4 years after college, in the "real world". Then I slowly came to realize the saying "this is 'real world' code--- the rules don't apply" was just a way of saying "I'm too lazy to do it right", and that the more I followed those rules they taught me in college, the better my code was.
Admin
Define "instantly". I'd conjecture that my way recognition takes 1/10 of a second, while your way takes 1/2 a second. You probably don't notice it at first, but across a page, it adds up. I thought I would recognize those idioms just as fast as the correct way, until I stopped using them and almost wrote the explicit form, and I soon realize how faster & easier it was to understand the code.
Well, I agree in principle, but it never helped me in practice. The problem is, if you can remember to write the constant first, you can remember to use two ==s. The one place where it is useful, is when the non-constant is a function call with a long parameter list:
if (MB_YES == MessageBox("An Error Occurred. Shall I continue?", MB_YESNO))
That way it keeps all the important points ("if", "MB_YES", "MessageBox") together, so you don't have to scan the entire line to know what's going on.
Admin
"Best"? I'd like to hear your explanation why it's even "better" than mine.
Downside of yours: It's confusing: If you don't notice the semicolon at the end of the for() statement, you'll greatly misinterpret what it's doing. (And, of course, if you forget the semi-colon weird things happen).
It's also an abuse of the for() statement. (if you'd used a while statement, I'd object less)
int i =0;
while ( i < somecount && a[i] != target)
++i;
The downside there is that it take attention away from the important part (a[i]!=target) and places it on a triviality (++i).
Note that each version generates object code which is byte-for-byte identical (Visual C++ 2003, Release build)
Admin
With the performance improvements suggested by JamesCurran and the bug fix noted by Ben Hutchings incorporated here is the final (hopefully) code.
For those who object tothe use of goto/break/continue, I'd be interested in seeing how you would rewrite this code without the use of the break keyword.
While the original code contains a couple of bugs and is unreadable it did have the following positive aspects.
Admin
No, no, no. Under no circumstances I would say that "real code" = "sloppy code". My point is that statements like "never use that operator" and "never use this keyword" are inherently wrong. They're wrong due to one simple fact: we can't predict the future. No matter how infrequent some language feature is there can be situation when using this unpopular feature is "the right thing to do".
This is what makes difference between novice and experienced mature developer. Experienced one will never do absolute statements because he knows well that reality is too diverse. We all have our rules of thumb, but we don't follow them blindly, but rather question those rules each time we use them.
Admin
See above..
Drak
--
The wheel should be reinvented until it rolls smoothly, is easy to build, and requires no maintenance.
Admin
No, you are giving up a very specific and limited set of rights. You are giving up your exclusive rights to copy, modify, distribute, prepare derivitive works of, and publicly display/perform the work in question. There is no reason not to do this for code you don't want to keep under your exclusive control. Doing something useless like saying "you may use it freely" causes the internet to be full of dead code that people can't use for fear of later lawsuits. If you don't wish to maintain exclusive rights to a work, making it public domain is exactly what you should do. Otherwise, you need to release it under a legally binding license, or nobody can use it at all.
Admin
But to accomplish that, you had to break the "one return rule" and with it duplicate the closing code (which is why there is a 1RR) three times. One the whole, a far may heinous crime.
Admin
When adherence to stuff like the "one return rule" leads you into writing code that's harder to read and/or maintain than it has to be, it's bad. I have seen people tie themselves into absurd knots trying to stick to one arbitrary dogma or another, and it's nonsense. Yes, a sufficiently ingenious programmer can get things done with all manner of inappropriate constructs, but that's not to say he should.
The prohibition on <font face="Courier New">break</font> in loops is the work of an imbecile. There's no way to be tactful about that one. The moron who dreamed it up probably thought <font face="Courier New">break</font> should be banned because it resembles <font face="Courier New">goto</font>, but that's insane: Sure, there's a jump in both, but all flow-of-control constructs involve jumps.
Programming is like writing or cooking or driving a car: Learn the rules, learn to think for yourself, and when the time comes to break the rules, be sure you know what you're doing. I wouldn't want a college freshman running around loose with <font face="Courier New">goto</font>, or automatic weapons, or powerful explosives. But I'd hate to have to try to get by without those tools myself.
JamesCurran, until constant-on-the-left becomes a habit, it helps focus your mind on the expression; after it becomes a habit, you won't be paying close attention again and you'll want the warning.
You're absolutely right about the MB_YES thing, of course. Much more clear that way. MessageBox() would be my number-one example, too.
Admin
"People who started with C and then latter pick up a little C++ are considered dangerous."
Isn't Bjarne one of these bastards? [:P][<:o)]
Admin
Why would they think that: strcpy returns a pointer to str, so that should never be 0.
Maybe you were thinking of strcmp(), which returns a useful if slightly unintuitive value... The C standard libraries do that a lot (esp. the functions that return 0 on success something else on error - it's mostly to do with the absence of exceptions, multiple return values and garbage collection). That doesn't make it a WTF to use ! on the value returned by such a function - it just means that C can be very unintuitive because of its low-level design.
Note to other people balking at goto() - since C has no exceptions and garbage collection, using goto()s in C can be a lot cleaner than the alternatives.
Admin
I like to call code like what you are describing from that crowd as "C+"
Admin
Admin
c = *from++;
I see this one scattered throughout the code. It seems like he's trying to "walk the pointer" and dereference it. But then shouldn't he doing this?
c = *(from++);
Because, after all, isn't this the default effect?
c = (*from)++;
I haven't really read much into the code. Maybe he is trying to do a variable increment and not a pointer-walk. Can anyone shed some light on this?
Admin
No, actually, it does the same as:
c = *(from++)
Postincrement has a higher precedence than dereference. It's actually a somewhat common idiom.
Admin
<FONT style="BACKGROUND-COLOR: #efefef">Isn't this point moot?</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">Doesn't</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">c = (*from)++; put the same value into "c" as:</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">c = *(from++)</FONT>
<FONT style="BACKGROUND-COLOR: #efefef">?</FONT>
Admin
Re: my previous post. Re: (*from)++ vs. *(from++)
Doh!
Hope everyone enjoyed my extra WTF.
Admin
The issues of gotos, bools, and so forth are secondary to the real problem with this: the obvious solution of converting the hex value to an <font face="Courier New">int</font>, then convert the <font face="Courier New">int</font> to the needed decimal string, is both simpler and faster than trying to perform some kind of textual transform for what is, in point of fact, a representation of a numeric value. This can be done in two lines of C code using standard library functions, and given the essential efficiency of the basic algorithmss in question, would probably be faster than any textual transform by an order of magnitude.
Admin
I agree, Irrelevant. Breaks are also very good for nested loops in my experience, and they get a bad wrap.
<font face="Courier New">
x = rs.getNextRecord()
while(x)
{
fieldVal = x->field1;</font><font face="Courier New">
echo '<h1>' . fieldVal . '</h1>';</font>
<font face="Courier New"> while(fieldVal == x.field1)
{
fieldVal2 = x->field2;</font><font face="Courier New">
echo '<h2>' . fieldVal2 . '</h2>';
</font>
<font face="Courier New"> while(fieldVal2 == x->field2 && fieldVal == x->field1)
{
doStuff(x);
doInnerEndStuff();</font><font face="Courier New">
x = rs.getNextRecord();</font>
<font face="Courier New"> if(!x) break;
}
doSecondEndStuff();
if(!x) break;
}
doOuterEndStuff();
}
</font><font face="Courier New"></font>
Admin
In that case I would feel justified using a goto.
If Not Done makes me ill :P
Admin
It's legal but not legible.
If size were used as a boolean variable here, applying a boolean operator like '!' would be fine. Instead, size holds the number of characters (in *to, presumably).
So size is used as a number, and comparison should be used, e.g. size != 0.
Welcome to the next level of understanding.
Admin
Except that once you start with C++, derive your own classes and write operator==(), interesting things begin to (not) happen...
In C++, more people should do the const keyword thing.
Admin
Nobody forces you to write non-intuitive things as long as there are legal alternatives. strcmp() becomes quite intuitive when you compare its result value against 0. That's how it was meant to be used; unfortunately the man page doesn't explain that.
Of course, that applies only if you write the 0 constant last, as one does naturally (i.e. as one learned in maths).