Richard<rg****@gmail.comwrites:
I'm still battling with this causing UDB:
while(e-- s);
if s points to the start of a string and e becomes less than s then e is
not really pointing to defined char. Fine.
But UDB?
A small note: You're the only person I've ever seen refer to undefined
behavior as "UDB". Most posters here (at least those who choose to
abbreviate it) refer to it as "UB". Why do you feel the need to
invent your own abbreviation when there's already a perfectly good one
in widespread use? (One could argue that "UB" could also mean
unspecified behavior, but i've never seen it used that way, and it's
generally clear enough from the context.)
Yes, the behavior is undefined, simply because the standard doesn't
define the behavior. That's all "undefined behavior" means.
Yes, e has an UDV (undefined value) but would this really cause a
program to misbehave? In any platfrom? Remember this value of e is never
used again in this case.
Yes. I don't have a real-world example, but if the containing object
happens to be allocated at the beginning of a memory segment, it could
easily blow up. And, as has been mentioned elsethread, a compiler is
allowed to *assume* that undefined behavior does not occur, and
perform code transformations based on that assumption (after all, if
the behavior is already undefined, it can't make things worse); that
may be a more realistic risk for most modern systems.
I ask because theoretically s can be pointing to the middle of a bigger
string. We then call a function with s as a parameter.
Undefined behavior occurs if a pointer is decremented past the
beginning of an array object, not if it's decremented past the initial
value of a function parameter. Given this:
char s[100];
char *func(char *ptr) { return ptr - 1; }
calling func(s+10) has well-defined behavior, but calling func(s) has
undefined behavior. (I haven't compiled the above, so there may be
some dumb mistakes.)
The function called can have no idea that s is the pointer to a middle
string.
Right.
therefore it can have no idea how to "do undefined things" when
e is decremented past the start of s. e and s are strictly char *s.
It doesn't deliberately "do undefined things"; that's not the point.
The point is that the standard doesn't define what it does. In my
example above, I'm thinking of a hypothetical system on which
constructing the pointer value s-1 causes a hardware trap (because s
is allocated at the beginning of a segment, and the hardware
"decrement address" instruction traps in this case). The code
generated for the body of the function has no awareness of this.
For example, assume an implementation on which signed integer overflow
causes a trap.
int func(int n) { return n + 1; }
func(42) has well-defined behavior, and returns 43. func(INT_MAX) has
undefined behavior, and (on this particular implementation) causes a
trap (or does something arbitrarily strange if an optimizing compiler
rearranges code based on the assumption that no UB occurs). The
function has no awareness of this; it just returns the result of n +
1.
It
would be so "not C" if the compiler generated code to check the contents
pointed to do determine the range of the object to the middle of which s
points. I mean then we may as well have array limits and exceptions
built into the language.
The compiler is *allowed* to perform such checks, but it's not
required to. That's why the behavior is undefined, rather than being
defined to do whatever a failing check would do.
I'm not being difficult here. Explain how this works. My problem (and I
admit its a problem) is that i feel too much of C is being elevated to
an almost ADA type status and (in this group) C is losing that "down and
dirty and efficient" feeling which it is famous for.
(It's "Ada", not "ADA".)
C loses none of its "down and dirty and efficient" feeling because of
this. In fact, the generated code can gain in efficiency because the
compiler is allowed to trust the user to avoid undefined behavior and
to perform aggressive optimization based on that assumption.
A C implementation that does exactly what you seem to expect it to do
(treat addresses as simple integers, allow arbitrary addresses to be
computed, etc.) would be conforming. An implementation that performs
aggressive bounds checking can also be conforming.
--
Keith Thompson (The_Other_Keith)
ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"