James Dow Allen said:
JohnF said:
It also somewhat tarnishes my picture of C the way it's often
described as a "portable assembly language". In that picture, I'd
kind of hope that strcpy would just assemble to some straightforward
move instruction, along with whatever '\000' end-of-string check
is available in the particular instruction set. If they want
to add optimizations, they could at least reserve them for -O3,
or something like that.
As someone who also views C as a "portable assembly language"
[...] A key meaning in that phrase is C's determinism
Never heard that before. What, precisely, is "determinism"
supposed to mean in this context?
and if the end-result of strcpy() (when used
according to its rules!) is completely defined,
what's to complain about?
My personal (repeat, >>personal<<) complaint would be
that if C instructions aren't compiled/assembled in
a straightforward way to machine instructions, then
I can't reliably visualize the code I'm generating.
Although different instruction sets do differ, they
nevertheless typically have lots in common. As an
old assembly programmer, I kind of know what I should
be able to expect from something calling itself
a "portable assembly language". In particular, I kind
of know how something calling itself strcpy should
be compiled. And that implicit understanding tells me
that strcpy(s,s+n) ought to be safe (as long, of course,
as strlen(s)>n). And it also tells me, of course, that
the reverse strcpy(s+n,s) is totally ridiculous.
It isn't clear whether you were unaware of strcpy()'s
overlap caveat or were but chose to ignore it (?!).
Hint: read this thread's Subject
As explained just above, I relied on the "portable
assembly language" idea to infer that strcpy(s,s+n)
would behave universally predictably and safely.
Won't make that mistake again. And I'd never have
made that mistake with, say, C++. But I'd like to have
thought that C (without optional -O3 type optimizations)
would compile straightforwardly/transparently/etc.
(the one-liner for strcpy() is famous!) and 99+% of
the time squeezing maximum efficiency is unnecessary.
Yeah, that's another good point. strcpy is typically (99+%)
used for parsing input, formatting output, etc, not within
heavy computational tasks. So optimizing strcpy is pretty
much a total waste, e.g.,
for (answer=0,i=0; i<10zillion; i++)
whatever;
format and display answer
in some way using sprintf,strcpy,etc;
What genius wastes his time optimizing the strcpy?
If your debuggable code accidentally passes NULL,
Segfault is exactly what you want
Might be what >>you<< want, but it's hard to speak for everybody.
Of course, I always check (except for blunders), and so don't
really care what it does. But I have lots of functions that take
optional char *args, which can be NULL or "\0" for default
behavior (and where I don't want to use variable arg lists).
Some checks would be unnecessary if strcpy, etc, just behaved
"nicely" when passed NULL's. But, again, I couldn't really
care less. My remark was just an observation, not a complaint.
(BTW, NULL == "" on some early Dig Equip C systems. This seemed not
necessarily bad, but obviously didn't "catch on"!
Can't recall what tops10 C did (I worked on the third ka10 processor
ever built), but vms's string (and other) descriptors were typically
a total pain in the neck.