removing a loop cause it to go at half the speed?


M

Mark McIntyre

Now this is interesting. Appendix J is informative, not normative,
so the fact that accessing an indeterminate object invokes undefined
behavior should be stated normatively elsewhere -- but I can't find it.

You can infer it from the rest of the text. You have to read it quite
hard.
Mark McIntyre
 
Ad

Advertisements

K

Keith Thompson

Mark McIntyre said:
You can infer it from the rest of the text. You have to read it quite
hard.

I'm not convinced that it can be inferred from the normative text, and
I tentatively believe that it can't. If you can convince me
otherwise, I'd be glad to see the evidence. (Of course, if you just
don't want to take the time to do it, that's fine too.)

In fact, ena8t8si wrote in a followup to my question:

] Appendix J just has it wrong in this case (probably for historical
] reasons). Accessing an uninitialized local is undefined behavior
] only if the indeterminate value can be a trap representation.

which seems plausible.
 
C

CBFalconer

arnold said:
.... snip ...
I understand, because you guys dont allways make it easy to
understand what it is you are actually saying. (I just experienced
that earlier today on this group, with the "i++ * i++" discussion),
so you could perhaps look a bit at why the person do not get what
you are saying and perhaps make an explanation more suited to the
understanding of the person.

Hell, if I could do that I might make a decent teacher. Many of us
are experts in inducing blank stares at the end of an explanation.
Then we just say the same thing louder, or with the odd clause
interchanged.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
M

Mark McIntyre

I'm not convinced that it can be inferred from the normative text, and
I tentatively believe that it can't. If you can convince me
otherwise, I'd be glad to see the evidence. (Of course, if you just
don't want to take the time to do it, that's fine too.)

We can agree that the value is indeterminate from 6.2.4 (5) and 6.7.8
(10).

We can agree that indeterminate values include traps from 3.17.2(1)

We can agree that undefined behaviour is "behavior, upon use of a
nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements" from
3.4.3 (1)


I assert that the value of something indeterminate is nonportable,
since what is a trap on one implementation could be valid on another.

I therefore assert that using an indeterminate value is nonportable,
and since the standard places no requirements on this action, its
undefined.

QED?
Mark McIntyre
 
E

ena8t8si

Mark said:
We can agree that the value is indeterminate from 6.2.4 (5) and 6.7.8
(10).

We can agree that indeterminate values include traps from 3.17.2(1)

We can agree that undefined behaviour is "behavior, upon use of a
nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements" from
3.4.3 (1)


I assert that the value of something indeterminate is nonportable,
since what is a trap on one implementation could be valid on another.

I therefore assert that using an indeterminate value is nonportable,
and since the standard places no requirements on this action, its
undefined.

Except when accessed as unsigned char, which has no trap
representations.
 
Ad

Advertisements

M

Mark McIntyre

Except when accessed as unsigned char, which has no trap
representations.

I thought so too, but I'm having trouble finding that demonstrated in
the Standard.
Mark McIntyre
 
E

ena8t8si

Mark said:
I thought so too, but I'm having trouble finding that demonstrated in
the Standard.

"A byte contains CHAR_BIT bits, and the values of type
unsigned char range from 0 to 2**CHAR_BIT - 1." Hence
it has no trap representations.
 
K

Keith Thompson

Mark McIntyre said:
We can agree that the value is indeterminate from 6.2.4 (5) and 6.7.8
(10).

We can agree that indeterminate values include traps from 3.17.2(1)

We can agree that undefined behaviour is "behavior, upon use of a
nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements" from
3.4.3 (1)


I assert that the value of something indeterminate is nonportable,
since what is a trap on one implementation could be valid on another.

I therefore assert that using an indeterminate value is nonportable,
and since the standard places no requirements on this action, its
undefined.

QED?

Not quite.

The value is indeterminate, which means it can be either an
unspecified value or a trap representation. If we can prove that
there are no trap representations for the type, then it can only be an
unspecified value, which is, by definition, a valid value.

C99 6.2.6.1p3, along with the associated footnote, imply that unsigned
char has no trap representations.

For other integer types, if the size of the type in bits and the
limits of the type specified in <limits.h> are such that the number of
bits is exactly enough to represent all the valid values, we can
conclude that there are no padding bits, and therefore no trap
representations.

C99 7.8.1.1 says that the intN_t types, if they exist, have no padding
bits.

Digression {
Surprisingly, it doesn't seem to make this guarantee for uintN_t.
It says:

The typedef name uintN_t designates an unsigned integer type
with width N. Thus, uint24_t denotes an unsigned integer type
with a width of exactly 24 bits.

The "width" of an unsigned type is defined as the number of value
bits; it specifically doesn't include padding bits. So uint24_t
could have a size of 32 bits, including 8 padding bits, but
int24_t cannot have any padding bits.

In n1124, the third paragraph has been modified to mention a lack
of padding bits for both signed and unsigned types, but the first
two paragraphs are unchanged.

I'll post a question to comp.std.c.
}
 
R

Robin Haigh

Keith Thompson said:
Now this is interesting. Appendix J is informative, not normative,
so the fact that accessing an indeterminate object invokes undefined
behavior should be stated normatively elsewhere -- but I can't find it.

Sections 6.2.4 ("Storage duration of objects"), 6.7.8,
("Initialization"), and 6.8 ("Statements and blocks") all say that
says that the initial value of an automatic object is indeterminate,
but they don't say anything about attempting to access that value.

If the statement in J.2 is to be taken literally, then in this
program:

int main(void)
{
unsigned char x;
unsigned char y;
y = x;
return 0;
}

the assignment invokes undefined behavior. Clearly, the value of x is
indeterminate. Since an indeterminate value is either an unspecified
value or a trap representation, and since unsigned char has no trap
representations, it must be an unspecified value. By definition, an
"unspecified value" is a "valid value of the relevant type".

What normative text in the standard says that this is undefined
behavior? (There would have to be an explicit statement; the behavior
of the assignment is specified in 6.5.16.1.)


I raised a question recently about uninitialized automatic structs. I've
since discovered that the same question is dealt with in DR 222, and the
wording in N1124 is the result of that (TC2).

Your answer was the right one. The new wording says the struct can't have a
trap representation (without saying that it isn't indeterminate) and the
intent is that accessing the "value" is therefore not UB, on any platform.
And presumably can be done in a strictly conforming program, so long as the
value is discarded and the output doesn't depend on it.

However, DR 260 has some alarming new thoughts about indeterminate values
which seem to go beyond the definition as "unspecified value or [if
applicable] trap representation". (I'm also worried as to what this may be
saying about determinate values, though I'm not at all clear about that)
 
M

Mark McIntyre

The value is indeterminate, which means it can be either an
unspecified value or a trap representation. If we can prove that
there are no trap representations for the type, then it can only be an
unspecified value, which is, by definition, a valid value.

Agreed.
C99 6.2.6.1p3, along with the associated footnote, imply that unsigned
char has no trap representations.

ISTR that footnotes are non-normative but this looks good to me.
For other integer types, if the size of the type in bits and the
limits of the type specified in <limits.h> are such that the number of
bits is exactly enough to represent all the valid values, we can
conclude that there are no padding bits, and therefore no trap
representations.

This may well be true, on any given implementation. However its not
guaranteed by the Standard, and hence still leads to UB.

Mark McIntyre
 
Ad

Advertisements

R

Robin Haigh

Mark McIntyre said:
We can agree that the value is indeterminate from 6.2.4 (5) and 6.7.8
(10).

We can agree that indeterminate values include traps from 3.17.2(1)

We can agree that undefined behaviour is "behavior, upon use of a
nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements" from
3.4.3 (1)


I assert that the value of something indeterminate is nonportable,
since what is a trap on one implementation could be valid on another.

I therefore assert that using an indeterminate value is nonportable,
and since the standard places no requirements on this action, its
undefined.

QED?


Behaviour is only undefined if it's not defined, and defined includes
implementation-defined.

A conforming implementation can define any behaviour it likes, within areas
not defined by the standard.

Therefore, it's never possible to say that any code _always_ produces
undefined behaviour.

Therefore, when we say that code produces undefined behaviour, without
reference to platform, we can't mean "always". We can only mean that it
_may_ produce undefined behaviour, and is therefore non-portable and not
strictly conforming. However, that doesn't mean there's nothing more to be
said.


For example, it's implementation-defined whether plain char is signed or
unsigned. Either way, the requirements of the standard still apply. Maybe,
your code's behaviour is fully defined on an "unsigned" platform, but on a
"signed" platform, as a knock-on consequence, there are further
implementation-defined issues, and ultimately (and perhaps only for certain
inputs) you may run out of definitions of behaviour, and end up with UB.

In that case, the code is non-portable, and it would be true in a sense to
say that the code produces UB. But it's not really a relevant point unless
the portability of the code is the issue. There's still the question of how
the code behaves on the platforms that make saner choices, or on the inputs
where the behaviour is guaranteed anyway, and there the standard still
applies.

The compiler can't say "well I've documented this particular scheme (for
some issue where I'm required to), but some other compiler could have done
it differently, therefore I'm a free agent, call for the nasal demons."
(Otherwise, there wouldn't be any distinction between
"implementation-defined" and undefined)


Same here. Representations of integer types are implementation-defined, so
it's implementation-defined whether an int may contain a trap
representation, i.e a bit pattern that corresponds to no value. So code
which accesses an uninitialized int is strictly non-portable, even if we
suppress the variable outputs, in the sense that a conforming implementation
could be created which could document that certain bit patterns for an int
correspond to no value and that accessing such a bit pattern may have some
(defined or undefined) observable outcome (which therefore might be
different from what could happen on a different implementation).

But if the implementation says there are no int traps, then there's no UB --
until we get to the overflow issue, where similar considerations apply
again. An implementation could say that a trap representation is generated,
in which case the standard says UB, and then the implementation need say no
more, so UB it is. Or the implementation might say silent wrap-round to a
valid value, in which case the standard continues to impose requirements on
the subsequent behaviour.
 
M

Mark McIntyre

Behaviour is only undefined if it's not defined,

Yes. However you've missed off these important words "by the
standard".
Therefore, it's never possible to say that any code _always_ produces
undefined behaviour.

Thats incorrect. Undefined behaviour is, in the context of CLC,
behaviour "for which this international standard imposes no
requirements".

A given platform may indeed define the behaviour. That is however
nongermane to the point. Once you start relying on the behaviour of a
given platform, your code is no longer C.
Mark McIntyre
 
K

Keith Thompson

Mark McIntyre said:
On Sat, 18 Mar 2006 22:23:47 GMT, in comp.lang.c , Keith Thompson


This may well be true, on any given implementation. However its not
guaranteed by the Standard, and hence still leads to UB.

I think you may have missed the point.

*If* the limits and size of a particular type are such that the values
of the type take up all the available bits, then there can be no
padding bits for that type. The precondition may or may not be true
for any particular type (other than unsigned char) on any particular
implementation, but the statement as a whole, I believe, is
universally correct.

For example, I believe the following program:

#include <limits.h>
#include <stdio.h>
int main(void)
{
printf("In this implementation, ");
if ( CHAR_BIT * sizeof(unsigned short) == 16 &&
USHRT_MAX == 65535)
{
printf("unsigned short has no padding bits\n");
}
else {
printf("unsigned short may or may not have padding bits\n");
}
return 0;
}

wll always print a statement that's true for the implementation it's
running on. (I could have dropped the "may or may not", and even
reported the number of padding bits, if I had taken the time to test
for sizes other than 16 bits.)
 
K

Keith Thompson

Mark McIntyre said:
Yes. However you've missed off these important words "by the
standard".


Thats incorrect. Undefined behaviour is, in the context of CLC,
behaviour "for which this international standard imposes no
requirements".

A given platform may indeed define the behaviour. That is however
nongermane to the point. Once you start relying on the behaviour of a
given platform, your code is no longer C.

Robin isn't ignoring those important words; he specifically accounted
for them by invoking implementation-specific definitions of behavior.
For example, the standard doesn't define the behavior on signed
integer overflow, but an implementation is free to do so.

However, I think that Mark is correct as far as the terminology is
concerned. A note on the definition of "undefined behavior" says:

NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of
a diagnostic message), to terminating a translation or execution
(with the issuance of a diagnostic message).

(Yes, the note is non-normative, but I accept what it says unless it's
contradicted elsewhere.)

So even if an implementation defines the behavior of signed integer
overflow as the usual 2's-complement wraparound, the behavior is still
undefined. Strictly speaking, it's not even implementation-defined
behavior; "implementation-defined behavior" is a subset of
"unspecified behavior", and integer overflow doesn't meet that
definition.
 
C

CBFalconer

Keith said:
.... snip ...

For example, I believe the following program:

#include <limits.h>
#include <stdio.h>
int main(void)
{
printf("In this implementation, ");
if ( CHAR_BIT * sizeof(unsigned short) == 16 &&
USHRT_MAX == 65535)
{
printf("unsigned short has no padding bits\n");
}
else {
printf("unsigned short may or may not have padding bits\n");
}
return 0;
}

wll always print a statement that's true for the implementation
it's running on. (I could have dropped the "may or may not",
and even reported the number of padding bits, if I had taken the
time to test for sizes other than 16 bits.)

As long as ULONG_MAX > USHRT_MAX you can easily compute the count
of active bits in an unsigned short. Comparing that with CHAR_BIT
* sizeof(unsigned short) will expose any padding bits and possible
trap values. In fact you don't even need the ULONG_MAX condition,
since:

for (i = 0, n = USHRT_MAX; n; i++) n = n >> 1;

should give you the bit count in i.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
Ad

Advertisements

J

Jordan Abel

Behaviour is only undefined if it's not defined, and defined includes
implementation-defined.

A conforming implementation can define any behaviour it likes, within areas
not defined by the standard.

Yes, but only behavior that the standard SAYS is implementation-defined
"counts" for the purpose of "defined includes implementation-defined".
 
R

Robin Haigh

Mark McIntyre said:
Yes. However you've missed off these important words "by the
standard".


Thats incorrect. Undefined behaviour is, in the context of CLC,
behaviour "for which this international standard imposes no
requirements".

A given platform may indeed define the behaviour. That is however
nongermane to the point. Once you start relying on the behaviour of a
given platform, your code is no longer C.


In the context of the standard, "undefined behaviour" means undefined by the
standard, i.e. the standard imposes no requirements.

But the standard deals with everything piecemeal, one little situation at a
time. Always, the meaning is "if this situation arises, during the
translation or execution of the program, the standard imposes no
requirements". Never in discussing run-time behaviour, e.g. expression
evaluation, does it just say "this is bad code". Never does it say "the
possibility of this bad situation arising in some circumstances makes the
standard inapplicable in all circumstances".

Whether or not a UB situation (where the standard imposes no requirements)
is actually reached during execution is in general conditional, not
determined by the standard, maybe not determinable by the compiler. For
instance, this is strictly conforming

int main (void) {
int i = 0;
if (0)
(void)(i++ + i++);
return 0;
}

notwithstanding that 6.5/2 (undefined behaviour) would apply to the
execution of one of its statements, if that statement occurred in a
different program where it actually did get executed.

Whereas this is non-portable and not strictly conforming:

#include <limits.h>
int main (void) {
int i = 0;
if (CHAR_BIT == 9)
(void)(i++ + i++);
return 0;
}

Because clearly there can be conforming implementations on which a situation
can arise, during execution, where the standard imposes no requirements.

But yet the behaviour is completely defined by the standard (what else?) on
a platform where CHAR_BIT != 9. Having specified CHAR_BIT as 8, say, the
implementation then gets no further say in the matter of how the program
behaves. So is this "not C"?

Or, suppose I put something dodgy in an exit handler. Will the program ever
exit? Who knows? Is the program's behaviour completely determined by the
standard? We might never know. Is it C?

In general, you can't use the run-time behaviour of a program as a
code-validity criterion. In fact you can't discuss behaviour at all without
bringing in suppositions about the implementation. I know there's an
abstract machine, but what's the value of CHAR_BIT in the abstract machine?

This is precisely why they had to invent the term "undefined behaviour"
instead of just saying "invalid code" or "an error". It was never supposed
to be a synonym for "invalid", it was specifically contrived to deal with
the fact that almost all C programs (sources) are capable of exhibiting
undefined behaviour on some platform (on which they aren't intended to run)
and/or under some circumstances (excluded by the spec). To say that the
standard and the newsgroup have nothing to say about such programs is to
make the standard and the newsgroup useless.
 
J

Jordan Abel

Or, suppose I put something dodgy in an exit handler. Will the program ever
exit?

This is a perfect example - I suspect that determining, in general,
whether a given line of a program is reached is equivalent to the
halting problem. (the halting problem itself being a special case of
_that_, of course.)
 
Ad

Advertisements

M

Mark McIntyre

I think you may have missed the point.

I didn't actually. I understood that *if* all bit patterns could
represent values, then there could be no traps. I merely pointed out
that it wasn't relevant to the undefinedness in question since the
Standard doesn't require that behaviour.
Mark McIntyre
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top