With a suffficient warning level (e.g. -Wall on gcc, which should always be enabled anyway, together with -Wextra), compilers will complain about the '=' and ask you to add a pair of braces to make clear that this is actually intended:
while( (*this++ = *that++) );
It's also one of those cases where the C code matches the output assembly pretty well:https://www.godbolt.org/z/nz1jbz4Er
As far as "obfuscated C" goes, this is a very tame example though, it's just a straightforward usage of language features, which might look strange only when coming from other languages that don't have pointers or a post-increment operator).
Ironically, the compiler os likely to recognize this as a strcpy and replace it with a possibly vectorized implementation.
The code as written was described as beautiful, yet would not have passed -Wall.
It's those little things that can easily get you in C, and there are so many little things to consider.
And the code without braces is still entirely valid standard C, the warning is essentially just a lint to protect against typos (similar to JS linters warning about '===' vs '==').
The flaw was minor in this case because the identifier names and lack of body make the intention clear, but my point is that there are a lot of minor things in C that can come and bite you at any time.
Edit: You are right, I don't see a way this could have been implemented more readable without sacrificing some performance.
First thing I thought of was:
void cp(const char* from, char* to) {
while (*from) {
*to = *from;
to++;
from++;
}
}
But that does not reduce to the original case.As for performance: I don't think such details matter much, first, compilers are pretty good to turn "readable but inefficient" code into the same optimal output (aka "zero cost abstraction").
And a really performance-oriented strcpy() wouldn't simply copy byte by byte anyway, but try to move data in bigger chunks (like 64-bit or even SIMD registers). Whether this is then actually faster also depends on the CPU though.
char c;
do
{
c = *src++;
*dst++ = c;
}
while (c != 0);
The post-increment is idiomatic enough in C-based languages that I wouldn’t worry about that.It is a shame post-test loops aren’t more popular, given the similarity to the assembly they output. Seems more mechanically sympathetic. Oh well, at least it is an excuse to whip out the goto.
repeat
...
until c = 0;
which might be even clearer for this use case.The order things happen in *this++ is not obvious unless you know a bunch of C-specific rules, while the ordering of multiple statements is obvious even to someone who doesn't know C. Perhaps C programmers should find this obvious, but it seems to me more like cognitive overhead which has a non zero chance of confusing someone at some point.
E.g. I guess for a mathematician, all imperative languages are probably 'weird', while something like Haskell feels more familiar?
This isn't a "clever one-liner" it is a clear and precise syntax for expressing the operation the machine actually performs.
while(copy(current(stream_a), current(stream_b)) and not end_of_stream(stream_a))
You might prefer the above, but then, that's every other major language. The beauty of C is that the above code has to compile to something like the C version. C just allows you to actually express it
No it’s not. Your compiler will almost certainly translate this into vector instructions, at least.
You shouldn't just blindly let your tooling dictate how you work. It's a tool that's supposed to work for you, not control you. -Wall and -Wextra are good baselines but I always disable some of their warnings because I don't need the hassle on known good code.
There's little more useful to say here, other than I don't think most people would agree with your view of what HN is.
It's a discussion forum, not an exegetical seminar. "On topic" is whatever the topic of discussion is; and this is not constrained to the article.
[ ] My comment is on-topic and positive to neutral
[ ] My comment is critical
[ ] My comment is off-topic
You've got to select one. When viewing, the comment thread defaults to just showing on-topic, non-negative comments, but you can see the other stuff, too, if you want.
This solves two seemingly contradictory desires: the ability to read comments on things that interest you without having to fend off waves of negativity and wade through pools of offtopic text and the ability to speak freely.
Think of it as very roughly analoguous to the different sections of a newspaper.
As someone who hasn't used C as a primary language in some project for over a decade, I read this and (1) realize that LHS and RHS both post-increment, (2) don't remember if there is some UB I might be overlooking, (3) realize that the operator is assignment "=", not comparison "==", and I can't even remember what the loop termination criterion here would be. Until "**that++" is equivalent to false, or something?
It may be beautiful to the experienced programmer, but I personally would consider this just "clever" (which is a criticism, not a compliment). It feels like someone needlessly tried to pack everything into a single line of code.
This is something I'd write out more verbosely, if only to make reading it simpler. The compiler will probably generate the same machine code either way.
I'm fully aware that to the seasoned C developer, my criticism might come across as naive. However, even the fully seasoned C developer can get careless, or become tired, and in C, every one of those little things can come back and bite you in those situations.
Edit: removed the double pointer dereferencing remark, must have been an artifact from HN's special treatment of the asterisk.