- Feature Articles
- CodeSOD
- Error'd
- 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
TRWTF is reinventing the
strtok
/strtok_r
wheel.Admin
Yop, it's weird. Nothing added there, no shadow copy, no variable length delimiter, it's straight up the same destructive method.
Admin
There is a subtle difference between strtok() and this code - libc-s strtok() skips empty values between tokens. So if your data is
foo::bar
then strtok() happily finds two values - "foo" and "bar". This code also finds the blank string between them.Admin
TRWTF is C's looping mechanisms that allow things like Duff's device and this while/while monstrosity.
Admin
Most languages would allow this while/while thing. Most languages allow you to write
while(condition);
and don't complain. That's all this is.Admin
Aside from the double while typo, which will be ignored by the compiler anyway, this seems fine.
Admin
strtok()
also only does one iteration of this loop and requires the caller to repeatedly call it, using the heinous implementation of storing global state and having a null pointer input mean to continue processing the same input (hence the need forstrtok_r()
). This implementation also eliminates using global state (good), but it always fully tokenizes the input and doesn't give the caller the option of only tokenizing it once or a few times (which may be fine for this particular application).Admin
But but but it's portable!
Admin
strtok()
is often used in loops similar to this one.Admin
It's not guaranteed to be ignored, especially if you've disabled optimisations. It won't generate much codecitation needed, but it won't necessarily generate none at all. (If optimisations are disabled or if the condition of the two while()s involves a function call, it must evaluate the second while()'s condition once, or the presence of the optimiser can be detected.)
(1) I did work with a compiler once (in 1992) that, in its most "aggressive" optimisation mode, when presented with a
while(1)
deliberately infinite loop, generated code to load a 1 into a register, then compare it to zero, and only branch back to the beginning of the loop if the 1 didn't match the 0...Admin
Case fall-through is a deliberate feature of C, not an oversight. When used as intended it avoids needless duplication of code, which is not "monstrous", but beautiful.
Admin
So you end up with something like a string array except you can't tell where the end is?
Admin
"Interesting topic! String in the colon is a serious issue that requires medical attention. It’s crucial to address such concerns with proper care and professional advice. Thanks for bringing awareness to this topic. Do you have any additional information or resources for those dealing with similar issues?"
Admin
right up until you have to maintain it
Admin
Among other WTFs, the
thing is just nasty and requires you to know far too much about the language.
is harder to type but much much easier to read.
Admin
Nothing helps with maintaining code as much as having less to maintain.
Are you really going to claim that C demands knowing more syntax than other industry languages? Really?
Admin
Fall-through in
case
statements is fine in principle; it just should be explicit. Imagine a setup where fall-through is triggered bycontinue
, and it's a compile-time error for any code path in a (non-empty) label to reach the start of the next label. You can still abuse it, if you really want to, but I feel like that's on you (as opposed to the current setup, where it's easy to do the wrong thing by accident).Admin
If you explicitly tell the compiler not to ignore it, then it won’t ignore it, but then TRWTF would be releasing unoptimised builds. And I wouldn’t have said the compiler would ignore the additional while condition if it contained code that couldn’t be ignored.
In practice, every compiler I have immediate access to (back to 1998’s Visual C/C++ 6.0) when presented with this specific code, ignores the additional while clause unless I explicitly /Od to tell it not to.
Admin
"ignores" is the wrong word. It must not actually ignore it. It's allowed to generate no code if there are no side effects, but it has to inspect it to see if there are actual or potential side-effects. (Or use of
volatile
variables...)Admin
I’m happy that my use of “ignore” accurately and succinctly conveyed my meaning. If it didn’t for you, then I’m also happy for you to parse my comments and replace the use of that shorthand with whichever construction of the concept “generates no output” you find appropriate.
Admin
If I see a comment posted by Anon, I could simply choose to not read it. Or I could read it and simply choose to not respond to it. Either way, from Anon's perspective, I have ignored his comment. But in the latter case, I did not truly ignore it.
This is the distinction being made by Steve_The_Cynic and it is an extremely important one.
Admin
Sure, many other languages (ones with C-like syntax) also allow you to do this, but the culture is such that C programmers write such "clever" code more often. I'm referring to things like using an expression for both its side effect and its value. (And here that value is used inside another expression with a side effect!)
I find the example with separate statements much more readable. One side effect per line.
Kernighan's law:
Admin
I'm reminded of how BASIC on e.g. the Commodore 64 turned out to leave the program code in a munged state after a certain int-overflow situation, because it destructively modified a string within the program code (and then crashed out before undoing the damage).
Admin
*p++ = <something> is a common idiom in C. I would argue that if you don't understand C, then you shouldn't use it. Let's not restrict ourselves to a subset of language features to please those who don't know what they're doing.
Admin
I agree that it's idiomatic, but I'd also argue that it's a bad practice that has become a convention. Statements should do one thing- putting two mutations in the same line makes it harder to reason about what that line does. I don't care how used to it you are, it's a risky anti-pattern.
Admin
It has no risk. Its behavior is defined. The same complaint might be raised about eager condition operations and else clauses ("An if statement should guard only one block!") and Dijkstra in fact did raise those complaints. But if you impose those kind of constraints on a project, you are effectively creating your own torment nexus of low expectations and overwrought code.
Admin
As I said, I’m happy that my use of “ignore” accurately and succinctly conveyed my meaning.
Admin
Sorry I have to disagree, C's string handling leaves a lot to be desired from a programmer's ease of life PoV, but given the standard C string idioms *p++ is exactly what the pre-and post increments are designed for and a key part of the C pointer manipulation toolset.
Having programmed in C since K&R was the "standard" I see this and know instinctively what's going on. reductive single-statement programming makes me feel like I'm back in cobol world again. If you don't like pointers you should probably not be programming in C.