Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #101118 > unrolled thread
| Started by | Manfred <noname@invalid.add> |
|---|---|
| First post | 2017-01-04 19:46 +0100 |
| Last post | 2017-01-30 12:05 -0800 |
| Articles | 18 on this page of 78 — 13 participants |
Back to article view | Back to comp.lang.c
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: lvalues from the ternary op Manfred <noname@invalid.add> - 2017-01-04 19:46 +0100
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-04 11:08 -0800
Re: lvalues from the ternary op Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-04 21:10 +0000
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-04 13:48 -0800
Re: lvalues from the ternary op Ian Collins <ian-news@hotmail.com> - 2017-01-05 11:07 +1300
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-04 14:20 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-04 14:41 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-04 15:21 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-04 15:52 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-04 16:37 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-04 18:31 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-13 17:26 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-13 17:49 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-15 22:53 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-13 17:08 -0800
Re: lvalues from the ternary op Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-14 02:15 +0000
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-15 22:51 -0800
Re: lvalues from the ternary op luser droog <luser.droog@gmail.com> - 2017-01-16 23:09 -0800
Re: lvalues from the ternary op Manfred <noname@invalid.add> - 2017-01-18 14:51 +0100
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-18 09:59 -0800
Re: lvalues from the ternary op Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2017-01-18 13:12 -0500
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-18 12:11 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-18 12:45 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-18 14:07 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-18 14:40 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-18 16:10 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-18 18:08 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-19 06:44 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-19 08:40 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-19 12:32 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-20 06:01 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-20 08:15 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-20 10:51 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-20 11:32 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-20 13:41 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-23 07:04 -0800
Re: lvalues from the ternary op Ike Naar <ike@iceland.freeshell.org> - 2017-01-23 17:59 +0000
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-23 10:57 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-31 08:45 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-01-31 09:13 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-31 10:17 -0800
Re: lvalues from the ternary op Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-01 01:51 +0000
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-01 14:24 -0800
Re: lvalues from the ternary op Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-02 03:07 +0000
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-04 04:43 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-04 08:01 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-09 09:06 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-09 11:56 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-12 10:29 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-12 13:43 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-19 21:44 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-20 08:15 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-24 07:58 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-24 10:00 -0800
Re: lvalues from the ternary op scott@slp53.sl.home (Scott Lurndal) - 2017-02-24 18:58 +0000
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-24 13:03 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-02-24 14:11 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-02-24 12:42 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-02-24 13:49 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-24 13:58 -0800
Re: lvalues from the ternary op Keith Thompson <kst-u@mib.org> - 2017-02-24 14:56 -0800
Re: lvalues from the ternary op supercat <flatfinger@casperkitty.com> - 2017-02-25 14:00 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-25 09:23 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-25 09:43 -0800
Re: lvalues from the ternary op Kelsey Bjarnason <kbjarnason@gmail.com> - 2017-02-01 22:47 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-02 10:12 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-04 07:51 -0800
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-02-04 08:18 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-09 08:58 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-04 04:00 -0800
Re: lvalues from the ternary op Kelsey Bjarnason <kbjarnason@gmail.com> - 2017-02-04 09:35 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-04 09:35 -0800
Re: lvalues from the ternary op Robert Wessel <robertwessel2@yahoo.com> - 2017-01-31 13:36 -0600
Re: lvalues from the ternary op supercat@casperkitty.com - 2017-01-31 12:23 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-02-01 13:48 -0800
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-31 08:53 -0800
Re: lvalues from the ternary op Manfred <noname@invalid.add> - 2017-01-19 14:10 +0100
Re: lvalues from the ternary op Tim Rentsch <txr@alumni.caltech.edu> - 2017-01-30 12:05 -0800
Page 4 of 4 — ← Prev page 1 2 3 [4]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2017-02-24 14:56 -0800 |
| Message-ID | <ln37f3i4ee.fsf@kst-u.example.com> |
| In reply to | #104650 |
supercat@casperkitty.com writes:
> On Friday, February 24, 2017 at 2:42:07 PM UTC-6, Keith Thompson wrote:
>> supercat writes:
>> > True or false: the Standard specifies as a runtime constraint that stored
>> > value of an object of type "float" may not be accessed with an lvalue of
>> > type "unsigned". Because this is a runtime constraint, the Standard
>> > allow implementations to do anything whatsoever if code violates it. Such
>> > permission overrides anything else in the Standard that would otherwise
>> > define the behavior of the code.
>>
>> False. The term "runtime-constraint", introduced in C11, applies only
>> to calls to library functions specified in the optional Annex K.
>
> I believe that if the structure of a program violates a "shall" clause in
> the Standard in such a way as to require a diagnostic, such violation is
> referred to as a constraint violation.
Yes. More precisely, a "shall" clause in a paragraph that's explicitly
labeled as a "constraint" is a constraint, and violating it requires a
diagnostic.
Do you think that your rephrasing of concepts already defined by the
standard is helpful? I don't.
> That would suggest that at least
> as far as ordinary English construction is concerned, a "shall" clause
> which is only applicable to run-time behavior would be a run-time
> constraint, though I see that a similar phrase with different hyphenation
> has been given another meaning.
I see, so "runtime constraint" is a phrase of your own invention. (I'm
guessing you weren't familar with Annex K?)
It doesn't suggest that to me. The word "constraint" has a very
specific meaning in the C standard, and that meaning does not apply to
run-time behavior (other than runtime-constraints, but that phrase
should be thought of as a single term; a runtime-constraint is not a
constraint).
> Since the phrase "a 'shall' or 'shall not' requirement that appears outside
> of a constraint or runtime-constraint" is a bit unwieldy, perhaps you can
> suggest something more to your liking?
What's wrong with calling it "undefined behavior", a term that almost
everyone here already understands perfectly well? "Undefined behavior"
also covers things other than violations of "shall" clauses.
4p2:
If a "shall" or "shall not" requirement that appears outside
of a constraint or runtimeconstraint is violated, the behavior
is undefined. Undefined behavior is otherwise indicated in this
International Standard by the words "undefined behavior" or by
the omission of any explicit definition of behavior. There is
no difference in emphasis among these three; they all describe
"behavior that is undefined".
[...]
> Most forms of Undefined Behavior are undefined by omission.
I'm skeptical of that claim, but I don't think it matters whether it's
valid or not.
> By contrast,
> code which violates "a 'shall' or 'shall not' requirement that appears
> outside of a constraint or runtime-constraint" invokes UB even if behavior
> would be defined in the absence of that requirement.
I suppose so.
[...]
>> > True or false: the Standard allows an implementation to process the
>> > statement "uf.u = 4;" in a way that writes to the stored value of the float
>> > value stored within "uf".
>>
>> I suggest wording this more clearly. One can write to an object, not to
>> a value; writing to an object updates the value that's stored in that
>> object.
>
> The Standard uses the phrase "have its stored value accessed" in 6.5p7;
> but I don't see any definition for "stored value". An action that modifies
> something, however, would appear to be a write and consequently an "access".
The definition of "access" is "<execution-time action> to read or modify
the value of an object". An object can be accessed; a value cannot.
[...]
>> It's quite possible that the standard's wording on union members is
>> internally inconsistent (that "quite possible" is mostly reflective of
>> my current state of ignorance on the matter). One particular question
>> I'm curious about is whether the footnote in 6.5.2.3:
>>
>> If the member used to read the contents of a union object is
>> not the same as the member last used to store a value in the
>> object, the appropriate part of the object representation of
>> the value is reinterpreted as an object representation in the
>> new type as described in 6.2.6 (a process sometimes called
>> "type punning). This might be a trap representation.
>>
>> can be inferred from the normative wording of the standard.
>> (It clearly represents the intent of the committee. The question
>> is whether that intent is sufficiently clearly stated in normative
>> text.)
>
> If code violates a "shall" requirement that is only applicable at runtime,
> it invokes UB regardless of whether behavior would be defined in the absence
> of that requirement. If one part of the Standard would appear to define the
> behavior of certain actions, but most such actions would violate a "shall"
> requirement given in another part, the Standard's rules of construction
> would imply that the former is only applicable to those actions that comply
> with the latter requirement.
I'm unwilling to wade through all the stuff you've written here to
extract its meaning. If you'd like to start again, using
standard-defined terminology where appropriate and citing the standard
itself to support your points, I'll take a look.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | supercat <flatfinger@casperkitty.com> |
|---|---|
| Date | 2017-02-25 14:00 -0800 |
| Message-ID | <09037b55-e8a1-4a05-bcdd-d01f1f8b9ba8@googlegroups.com> |
| In reply to | #104655 |
On Friday, February 24, 2017 at 4:56:19 PM UTC-6, Keith Thompson wrote: > I see, so "runtime constraint" is a phrase of your own invention. (I'm > guessing you weren't familar with Annex K?) I'd forgotten about it, since I had no use for it. I wouldn't call the phrase a term of my own invention so much as it was a combination of the adjectival phrase, "run-time", and the English language word "constraint" which, per dictionary.com, means 7. Linguistics. a restriction on the operation of a linguistic rule or the occurrence of a linguistic construction. > It doesn't suggest that to me. The word "constraint" has a very > specific meaning in the C standard, and that meaning does not apply to > run-time behavior (other than runtime-constraints, but that phrase > should be thought of as a single term; a runtime-constraint is not a > constraint). > > Since the phrase "a 'shall' or 'shall not' requirement that appears outside > > of a constraint or runtime-constraint" is a bit unwieldy, perhaps you can > > suggest something more to your liking? > > What's wrong with calling it "undefined behavior", a term that almost > everyone here already understands perfectly well? "Undefined behavior" > also covers things other than violations of "shall" clauses. What is needed is phrase that applies to a condition which must be met in order for a program's behavior to be defined. The phrase "Undefined Behavior" cannot serve that function. The Standard uses the terminology "a 'shall' or 'shall not' requirement that appears outside of a constraint or runtime constraint" could meet that function, but it seems a bit unwieldy. > > The Standard uses the phrase "have its stored value accessed" in 6.5p7; > > but I don't see any definition for "stored value". An action that modifies > > something, however, would appear to be a write and consequently an "access". > > The definition of "access" is "<execution-time action> to read or modify > the value of an object". An object can be accessed; a value cannot. The Standard uses the phrase "have its stored value accessed". If values cannot be accessed, what is the "shall" requirement in 6.5p7 supposed to mean?
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-25 09:23 -0800 |
| Message-ID | <kfn1sumrxpj.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #104639 |
Keith Thompson <kst-u@mib.org> writes: > [...] One particular question > I'm curious about is whether the footnote in 6.5.2.3: > > If the member used to read the contents of a union object is > not the same as the member last used to store a value in the > object, the appropriate part of the object representation of > the value is reinterpreted as an object representation in the > new type as described in 6.2.6 (a process sometimes called > "type punning). This might be a trap representation. > > can be inferred from the normative wording of the standard. As I read the Standard this conclusion does follow from normative text, yes. (see next) > (It clearly represents the intent of the committee. The question > is whether that intent is sufficiently clearly stated in normative > text.) Some time ago I took the trouble to go through the relevant passages in the Standard to answer this question. Taking a comp.lang.c perspective (rather than a comp.std.c perspective or "language lawyer" perspective), I find no cause for doubt, in the same sense that I find no cause to doubt that a (char*)(void*) conversion of a pointer gives the same value as just (char*) does, or that storing an abstract value in an object and then reading the object using (unsigned char) gives bytes of the object representation of the abstract value stored (and vice versa). The Standard doesn't come right out and say either of those things, but everyone accepts them as true. My impression is that the same level of confidence applies for the union member access question. And I think most people would have that same impression, if they take the time to look at all the different relevant sections, and adopt the perspective outlined above. I'm not going to frame an argument to "make my case", I'm just stating my thoughts on the matter. But if someone else goes through the exercise I'd be interested to hear their comments, and would be happy to discuss and compare their reactions with mine if that can be done in a non-argumentative way.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-25 09:43 -0800 |
| Message-ID | <kfnwpceqi77.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #104612 |
supercat@casperkitty.com writes:
> On Friday, February 24, 2017 at 9:58:56 AM UTC-6, Tim Rentsch wrote:
>> The problem you're having now is that your conclusions are not
>> consistent with everyone else's. Until you learn to express
>> yourself in a way that communicates effectively with other
>> people, /and vice versa/, that problem is not going to go away.
>> A tall order, I know, but there it is.
>
> The following questions assume the following declaration is in scope, and
> for questions about code, assume the scope is within some function and is
> executed.
>
> union { unsigned u; float f; } uf;
>
> True or false: the Standard specifies as a runtime constraint that stored
> value of an object of type "float" may not be accessed with an lvalue of
> type "unsigned". Because this is a runtime constraint, the Standard
> allow implementations to do anything whatsoever if code violates it. Such
> permission overrides anything else in the Standard that would otherwise
> define the behavior of the code.
>
> True or false: the Standard specifies that the above declaration will, among
> other things, create an object of type "float" which is stored within "uf",
> and such object will exist as long as containing "uf" object exists.
>
> True or false: the Standard specifies that the expression "uf.u" will
> is an lvalue of type "unsigned".
>
> True or false: the Standard allows an implementation to process the
> statement "uf.u = 4;" in a way that writes to the stored value of the float
> value stored within "uf".
>
> True or false: the Standard allows an implementation to process the
> statement "uf.u = 4;" in a way that would cause a stored value of type
> "float" to be accessed using an lvalue of type "unsigned", violating a
> runtime constraint.
>
> True or false: if any of the ways in which a conforming implementation
> could process an action invoke UB, the action itself invokes UB.
>
> If all of the above are true, they would imply that given the above union,
> an attempt to write member "uf.u" may be regarded as violating a runtime
> constraint, and would thus invoke UB, regardless of whether code makes any
> effort to use "uf.f".
>
> The only way I can see for the Standard to impose any requirements on the
> behavior of code which writes "uf.u" would be for the language of the
> Standard to be interpreted in such a way that at least one of the above
> true-false statements is false. I suspect that that any compiler that
> applied aliasing constraints to the above code for the purpose of
> disregarding everything else would be widely denounced as a piece of junk.
> Since the Standard acknowledges the possibility of conforming-but-useless
> implementations, however, I see no reason to believe it a compiler that
> interpreted aliasing rules as described could not be conforming.
You're making the same mistake as before. Your comments are
phrased in the style of making an argument for your point of
view. What you need to do instead is state your views explicitly
as being your opinion, eg, "I believe the Standard says an object
of union type contains one or more overlapping objects, one for
each member". Then, _after_ giving those views, ask about what
other people think and invite them to react or give their own
views or both. Maybe the most important point is to try to
listen rather than argue.
[toc] | [prev] | [next] | [standalone]
| From | Kelsey Bjarnason <kbjarnason@gmail.com> |
|---|---|
| Date | 2017-02-01 22:47 -0800 |
| Message-ID | <i91bmd-no6.ln1@spanky.localhost.net> |
| In reply to | #102853 |
[snips]
[PMFJI]
On Tue, 31 Jan 2017 10:17:02 -0800, supercat wrote:
> 6. The Standard authorizes compilers to do anything whatsoever if the
> storage of an object with one Effective Type is accessed using an
> lvalue of an incompatible type, and "int" is not a type compatible
> with "float".
This makes me wonder...
union {
type_1 a;
type_2 b;
} u;
Assume type_1 has no trap representations, while type_2 does; or each
does but they're different, and further assume they overlap such that
sizeof(u) is more or less the size of the largest, rather than the
combined size of each...
... let's ponder a pseudo-assembly code view of using this:
load 0x0fffffff into int_register_a
store int_register_a into [memory_address]
In our imaginary system, int_register_a can handle a bit pattern
associated with 0x0fffffff, while a floating point register cannot, it
would cause a trap.
If we subsequently did this:
load [memory_address] into int_register_a
we would not expect a trap, as [memory_address] has a legitimate
representation of a value for the register. If, instead, we did this:
load [memory_address] into float_register_f
we would expect a trap.
I submit that the correct semantics is that any valid value of o.a can be
stored into a, regardless of the details of o.b; and likewise it can be
retrieved from u.a without invoking u.b's behaviour.
Which suggests that what counts is not "accessing the storage *of* an
object", but, rather, accessing the storage *as* an object. As long as
object u.b is not accessed (without an intervening store of a legitimate
value into u.b), then there should be no unexpected behaviour, the
accessing of u.a should behave exactly as if u.a were a member of a
struct, rather than a union.
Or did I miss something?
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-02-02 10:12 -0800 |
| Message-ID | <4818f3ca-9f90-404d-8a5e-96469d12a466@googlegroups.com> |
| In reply to | #102948 |
On Thursday, February 2, 2017 at 12:58:03 AM UTC-6, Kelsey Bjarnason wrote:
> Which suggests that what counts is not "accessing the storage *of* an
> object", but, rather, accessing the storage *as* an object. As long as
> object u.b is not accessed (without an intervening store of a legitimate
> value into u.b), then there should be no unexpected behaviour, the
> accessing of u.a should behave exactly as if u.a were a member of a
> struct, rather than a union.
>
> Or did I miss something?
When C was designed, that was pretty much how things worked, and it made
C very useful for systems programming. Many implementations of other
languages had ways that arbitrary regions of memory could be accessed as
various types, but because such features were not inherent to those
languages different compilers--even for the same platform--would often
implement them in various ways. C became popular because it was one of
the first language that both providing a consistent syntax by which such
constructs could be expressed and also supported 8-bit types.
On the other hand, given something like:
float f;
int *p;
float test()
{
f=1.0f;
*p += 0x0100;
return f;
}
the authors of the Standard recognized that it would make sense not to
require that the compiler physically reload f from memory or otherwise
allow for the "dubious" possibility that *p might alias f.
The authors of the Standard figured that given some simple rules that would
allow compilers to ignore aliasing in cases where it would be unlikely to
be of much use, compiler writers could be relied upon to support aliasing
in other cases where it would be needed (which would vary with both the
target platform and application field; aliasing of "float" and "int" would
be rare in scientific code, for example, but common in floating-point
library code). If the authors of the Standard had wanted to describe all
the cases where they would have thought it obvious to everyone that aliasing
should be supported, that would have required much more complicated
definitions for "object", "access", etc. Since all that extra complexity
probably wouldn't have resulted in C89 compiler writers doing anything *that
they weren't going to do anyway*, that would have been a waste of time and
ink.
Unfortunately, the authors of later standards have been loath to change
fundamental definitions that seem to have "worked well", even if the only
reason that they worked was that compiler writers and programmers alike
had been glossing over the contradictions they posed.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-04 07:51 -0800 |
| Message-ID | <kfn4m0a9cox.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102966 |
supercat@casperkitty.com writes:
> On Thursday, February 2, 2017 at 12:58:03 AM UTC-6, Kelsey Bjarnason wrote:
>> Which suggests that what counts is not "accessing the storage *of*
>> an object", but, rather, accessing the storage *as* an object. As
>> long as object u.b is not accessed (without an intervening store of
>> a legitimate value into u.b), then there should be no unexpected
>> behaviour, the accessing of u.a should behave exactly as if u.a
>> were a member of a struct, rather than a union.
>>
>> Or did I miss something?
>
> When C was designed, that was pretty much how things worked, and it
> made C very useful for systems programming. Many implementations of
> other languages had ways that arbitrary regions of memory could be
> accessed as various types, but because such features were not
> inherent to those languages different compilers--even for the same
> platform--would often implement them in various ways. C became
> popular because it was one of the first language that both providing
> a consistent syntax by which such constructs could be expressed and
> also supported 8-bit types.
>
> On the other hand, given something like:
>
> float f;
> int *p;
>
> float test()
> {
> f=1.0f;
> *p += 0x0100;
> return f;
> }
>
> the authors of the Standard recognized that it would make sense not
> to require that the compiler physically reload f from memory or
> otherwise allow for the "dubious" possibility that *p might alias f.
>
> The authors of the Standard figured that given some simple rules
> that would allow compilers to ignore aliasing in cases where it
> would be unlikely to be of much use, compiler writers could be
> relied upon to support aliasing in other cases where it would be
> needed (which would vary with both the target platform and
> application field; aliasing of "float" and "int" would be rare in
> scientific code, for example, but common in floating-point library
> code). If the authors of the Standard had wanted to describe all
> the cases where they would have thought it obvious to everyone that
> aliasing should be supported, that would have required much more
> complicated definitions for "object", "access", etc. Since all that
> extra complexity probably wouldn't have resulted in C89 compiler
> writers doing anything *that they weren't going to do anyway*, that
> would have been a waste of time and ink.
>
> Unfortunately, the authors of later standards have been loath to
> change fundamental definitions that seem to have "worked well", even
> if the only reason that they worked was that compiler writers and
> programmers alike had been glossing over the contradictions they
> posed.
This description greatly mischaracterizes the history. It is
essentially purely a product of supercat's imagination.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-02-04 08:18 -0800 |
| Message-ID | <942abf19-48ab-4ec6-a3fd-1de993dae981@googlegroups.com> |
| In reply to | #103138 |
On Saturday, February 4, 2017 at 9:51:35 AM UTC-6, Tim Rentsch wrote:
> supercat writes:
>
> > On Thursday, February 2, 2017 at 12:58:03 AM UTC-6, Kelsey Bjarnason wrote:
> >> Which suggests that what counts is not "accessing the storage *of*
> >> an object", but, rather, accessing the storage *as* an object. As
> >> long as object u.b is not accessed (without an intervening store of
> >> a legitimate value into u.b), then there should be no unexpected
> >> behaviour, the accessing of u.a should behave exactly as if u.a
> >> were a member of a struct, rather than a union.
> >>
> >> Or did I miss something?
> >
> > When C was designed, that was pretty much how things worked, and it
> > made C very useful for systems programming. Many implementations of
> > other languages had ways that arbitrary regions of memory could be
> > accessed as various types, but because such features were not
> > inherent to those languages different compilers--even for the same
> > platform--would often implement them in various ways. C became
> > popular because it was one of the first language that both providing
> > a consistent syntax by which such constructs could be expressed and
> > also supported 8-bit types.
> >
> > On the other hand, given something like:
> >
> > float f;
> > int *p;
> >
> > float test()
> > {
> > f=1.0f;
> > *p += 0x0100;
> > return f;
> > }
> >
> > the authors of the Standard recognized that it would make sense not
> > to require that the compiler physically reload f from memory or
> > otherwise allow for the "dubious" possibility that *p might alias f.
> >
> > The authors of the Standard figured that given some simple rules
> > that would allow compilers to ignore aliasing in cases where it
> > would be unlikely to be of much use, compiler writers could be
> > relied upon to support aliasing in other cases where it would be
> > needed (which would vary with both the target platform and
> > application field; aliasing of "float" and "int" would be rare in
> > scientific code, for example, but common in floating-point library
> > code). If the authors of the Standard had wanted to describe all
> > the cases where they would have thought it obvious to everyone that
> > aliasing should be supported, that would have required much more
> > complicated definitions for "object", "access", etc. Since all that
> > extra complexity probably wouldn't have resulted in C89 compiler
> > writers doing anything *that they weren't going to do anyway*, that
> > would have been a waste of time and ink.
> >
> > Unfortunately, the authors of later standards have been loath to
> > change fundamental definitions that seem to have "worked well", even
> > if the only reason that they worked was that compiler writers and
> > programmers alike had been glossing over the contradictions they
> > posed.
>
> This description greatly mischaracterizes the history. It is
> essentially purely a product of supercat's imagination.
Sorry I forgot to add the qualifier "In the world outside comp.lang.c".
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-09 08:58 -0800 |
| Message-ID | <kfnzihv47xp.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #103143 |
supercat@casperkitty.com writes:
> On Saturday, February 4, 2017 at 9:51:35 AM UTC-6, Tim Rentsch wrote:
>> supercat writes:
>>
>>> On Thursday, February 2, 2017 at 12:58:03 AM UTC-6, Kelsey Bjarnason wrote:
>>>> Which suggests that what counts is not "accessing the storage *of*
>>>> an object", but, rather, accessing the storage *as* an object. As
>>>> long as object u.b is not accessed (without an intervening store of
>>>> a legitimate value into u.b), then there should be no unexpected
>>>> behaviour, the accessing of u.a should behave exactly as if u.a
>>>> were a member of a struct, rather than a union.
>>>>
>>>> Or did I miss something?
>>>
>>> When C was designed, that was pretty much how things worked, and it
>>> made C very useful for systems programming. Many implementations of
>>> other languages had ways that arbitrary regions of memory could be
>>> accessed as various types, but because such features were not
>>> inherent to those languages different compilers--even for the same
>>> platform--would often implement them in various ways. C became
>>> popular because it was one of the first language that both providing
>>> a consistent syntax by which such constructs could be expressed and
>>> also supported 8-bit types.
>>>
>>> On the other hand, given something like:
>>>
>>> float f;
>>> int *p;
>>>
>>> float test()
>>> {
>>> f=1.0f;
>>> *p += 0x0100;
>>> return f;
>>> }
>>>
>>> the authors of the Standard recognized that it would make sense not
>>> to require that the compiler physically reload f from memory or
>>> otherwise allow for the "dubious" possibility that *p might alias f.
>>>
>>> The authors of the Standard figured that given some simple rules
>>> that would allow compilers to ignore aliasing in cases where it
>>> would be unlikely to be of much use, compiler writers could be
>>> relied upon to support aliasing in other cases where it would be
>>> needed (which would vary with both the target platform and
>>> application field; aliasing of "float" and "int" would be rare in
>>> scientific code, for example, but common in floating-point library
>>> code). If the authors of the Standard had wanted to describe all
>>> the cases where they would have thought it obvious to everyone that
>>> aliasing should be supported, that would have required much more
>>> complicated definitions for "object", "access", etc. Since all that
>>> extra complexity probably wouldn't have resulted in C89 compiler
>>> writers doing anything *that they weren't going to do anyway*, that
>>> would have been a waste of time and ink.
>>>
>>> Unfortunately, the authors of later standards have been loath to
>>> change fundamental definitions that seem to have "worked well", even
>>> if the only reason that they worked was that compiler writers and
>>> programmers alike had been glossing over the contradictions they
>>> posed.
>>
>> This description greatly mischaracterizes the history. It is
>> essentially purely a product of supercat's imagination.
>
> Sorry I forgot to add the qualifier "In the world outside comp.lang.c".
You frequently offer up these sorts of speculations regarding the
thinking or motivations of the people responsible for the
Standard. AFAICT you never offer a scintilla of evidence that
might back up your hypotheses. You do sometimes offer arguments,
but no evidence, and arguments mean nothing without evidence.
Furthermore, when I have taken the trouble to look, in every case
I remember your suppositions are at odds with the evidence in the
historical documents of the ISO C working group. So if past
experience is any indication "the world outside comp.lang.c" is
actually just the world inside your own head.
I again invite anyone who is interested to look through the
historical documents of the ISO C working group, at
http://www.open-std.org/jtc1/sc22/wg14/www/docs/
and draw their own conclusions.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-04 04:00 -0800 |
| Message-ID | <kfnd1ey9ne2.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102948 |
Kelsey Bjarnason <kbjarnason@gmail.com> writes:
>> [accessing a union member when a different member was the
>> last member written]
>
> This makes me wonder...
>
> union {
> type_1 a;
> type_2 b;
> } u;
>
> Assume type_1 has no trap representations, while type_2 does; or
> each does but they're different, and further assume they overlap
> such that sizeof(u) is more or less the size of the largest,
> rather than the combined size of each...
Members of a union are guaranteed to overlap, and to start at the
same address, which is the address at which the union object as
a whole starts.
> [...]
>
> I submit that the correct semantics is that any valid value of o.a
> can be stored into a, regardless of the details of o.b; and
> likewise it can be retrieved from u.a without invoking u.b's
> behaviour.
Presumably you meant u.a and u.b there rather than o.a and o.b.
> Which suggests that what counts is not "accessing the storage *of*
> an object", but, rather, accessing the storage *as* an object. As
> long as object u.b is not accessed (without an intervening store
> of a legitimate value into u.b), then there should be no
> unexpected behaviour, the accessing of u.a should behave exactly
> as if u.a were a member of a struct, rather than a union.
How this is worded is a little funny so I'm not sure exactly
what you mean to say. But I think we can clear things up by
looking at a slightly different example.
We start with two scalar types, which I will call Smaller and
Larger, and with sizeof (Smaller) < sizeof (Larger). The type
Smaller has no trap representations (and more specifically, it
has one abstract value for each distinct set of bit values, so
there is a one-to-one mapping between its values and its object
representations). Also neither of these types is a character
type. We will leave aside for the moment the question of whether
the type Larger has any trap representations.
Now here is our union:
union { Smaller small; Larger large; } u = { 0 };
where the initialization is done just to avoid any funny
business with uninitialized values.
Given the above, it is always okay to access u.small, in the
sense that the result will never be undefined behavior,
regardless of whether u.small or u.large was the last member
assigned to. If u.small was the last member assigned to, reading
u.small will give the value that was assigned. If u.large was
the last member assigned to, reading u.small will take those
bytes of u.large that occupy the same memory as the bytes of
u.small, and interpret them as an object representation of
type Smaller, and give the abstract value that corresponds to
that object representation. Since the type Smaller has no
trap representations, the result is well-defined, although
what value comes out depends on what value was stored in
u.large, how that type is represented, etc.
Going the other direction, writing u.small and reading u.large,
what happens depends on whether the type Larger has or does not
have trap representations. Writing u.small gives defined bit
values for the bytes that u.small occupies, and unspecified bit
values for all other bytes of u (and in particular, for those
bytes of u.large that do not correspond to the bytes of u.small).
If the defined bits plus the unspecified bits happen to be a trap
representation for type Larger, boom!, it's undefined behavior;
if they happen not to be, all is okay, and we get some abstract
value of the Larger type (which depends on the bit values and on
how different object representations map onto a Larger value).
If the type Larger does _not_ have trap representations, then
reading u.large is always okay, and is very much like the reverse
situation, except that in this case some of the bits of u.large
would be unspecified if u.small were the member last written.
The above can be shown easily as a simple picture:
+--------+--------+--------+--------+--------+--------+--------+--------+
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
+--------+--------+--------+--------+--------+--------+--------+--------+
<---- u.small ---->
<------------- u.large ------------->
<----------------------------------- u --------------------------------->
Assuming sizeof (Smaller) == 2, sizeof (Larger) == 4, and unions
are always padded to a multiple of 8 bytes.
Note that there are exactly three objects. Storing a value into
the u.large object changes the values of the two bytes that make
up the underlying memory of the u.small object. Storing into an
object implies changing the values of bytes in the underlying
memory. But in the other direction, changing the values of
bytes that are (perhaps only some of) the underlying memory does
NOT imply that the other object was accessed. An assignment like
u.large = 7;
changes the bytes underlying the u.small object, but it is not
an access to u.small. Which object is accessed depends on not
just what bytes are affected but what source code does the
accessing. Does that all make sense?
If you are okay up to here, the last step is to keep the same
picture but now let the sizes of the two members be the same. We
still have three objects, with the two member objects coinciding
in terms of what bytes they occupy. Because the two types have
the same size, there are no unspecified bit values to think
about due to writing one member and reading another. Thinking
about the case when the members have different sizes helps
understand the case when their sizes are the same.
Does this explanation agree with what you were trying to say?
[toc] | [prev] | [next] | [standalone]
| From | Kelsey Bjarnason <kbjarnason@gmail.com> |
|---|---|
| Date | 2017-02-04 09:35 -0800 |
| Message-ID | <bvfhmd-o6q.ln1@spanky.localhost.net> |
| In reply to | #103128 |
[snips] On Sat, 04 Feb 2017 04:00:21 -0800, Tim Rentsch wrote: > u.large = 7; > > changes the bytes underlying the u.small object, but it is not an access > to u.small. Which object is accessed depends on not just what bytes are > affected but what source code does the accessing. Does that all make > sense? Precisely. > If you are okay up to here, the last step is to keep the same picture > but now let the sizes of the two members be the same. We still have > three objects, with the two member objects coinciding in terms of what > bytes they occupy. Because the two types have the same size, there are > no unspecified bit values to think about due to writing one member and > reading another. Thinking about the case when the members have > different sizes helps understand the case when their sizes are the same. > > Does this explanation agree with what you were trying to say? Indeed.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-04 09:35 -0800 |
| Message-ID | <kfnzii197v5.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102853 |
supercat@casperkitty.com writes:
> On Tuesday, January 31, 2017 at 10:45:31 AM UTC-6, Tim Rentsch wrote:
>> supercat writes:
>>> Given "union u { uint32_t x; float y; } u;", if both u.x and u.y
>>> are objects, which of the following can be said about the code
>>> "u.x = 1;":
>>>
>>> 1. The thing to the left of the equals is something other than
>>> an lvalue of type "uint32_t".
>>>
>>> 2. The code does not access the stored value of a "float"
>>> object.
>>>
>>> 3. The code invokes Undefined Behavior because it uses an
>>> lvalue of type uint32_t to access the value of a float
>>> object.
>>
>> The Standard is quite clear that unions (that have more than one
>> member) hold multiple overlapping objects (6.2.5 p20). Here u.x
>> and u.y are two distinct objects, and they overlap. If you think
>> that doesn't make sense then you're confused about something.
>
> Explain the error in my logic, [taking the following to be code
> inside a function defition] "union {int i; float f;} u; u.i=4;"
>
> 1. "u.i" is an lvalue of type "int".
Yes.
> 2. The statement "u.i=4;" writes to an lvalue of type int.
It writes to the object designated by u.i. The expression u.i is
an lvalue, what gets written to is the object designated by that
expression.
> 3. There exists an object, known as "u.f", whose declared type is
> "float".
The expression 'u.f' designates an object, which is inside the
object designated by 'u', and which overlaps the object
designated by 'u.i'.
> 4. The act of writing to that lvalue of type "int" also
> constitutes an access to the storage underlying u.f.
You need to learn to write more directly. Rather than saying
"The act of writing to that lvalue", say "Assigning to u.i". If
what you mean is something different than "Assigning to u.i", that
is an important problem and should be explained.
Assigning to u.i does affect (perhaps only some of) the bytes
of storage underlying the object designated by u.f, but does
not constitute an access to the u.f object.
> 5. Because u.f has a declared type of "float", its Effective Type
> is also "float".
The object designated by u.f has effective type float.
> 6. The Standard authorizes compilers to do anything whatsoever if
> the storage of an object with one Effective Type is accessed
> using an lvalue of an incompatible type, and "int" is not a
> type compatible with "float".
The Standard requires objects be accessed only by lvalues whose
types match the effective type of the object being accessed, as
spelled out in section 6.5 paragraphs 6 and 7.
> 7. The aforementioned code invokes UB.
Again you should write more directly. Rather than saying "The
aforementioned code invokes UB", you might say "The assignment
'u.i=4' does not adhere to effective type rules and so is
undefined behavior."
This conclusion is wrong. The assignment 'u.i=4' accesses the
object designated by u.i, but does not access the object
designated by u.f. The memory underlying the u.f object (or at
least some of it) is affected by the assignment to u.i, but
'u.i=4' does not constitute an access to the u.f object.
> In the absence of aliasing rules, there would be no problem with
> saying that if the bit pattern stored in "u" is a valid bit pattern
> for an "int" and also a valid bit pattern for a "float", the storage
> "represents" values of both types simultaneously.
A given object representation for u may very well be (perhaps in
part) a non-trap object representation for u.i and also be
(perhaps in part) a non-trap object representation for u.f,
regardless of effective type rules.
AFAIK the Standard does not use the term "represents" in the
sense that you are using it. So in a sense there is no problem
with saying "the storage [of u] 'represents' values of both types
simultaneously", except that nothing is being said - you are
using an undefined term and therefore the statement has no
meaning.
> I fail to see,
> however, how aliasing rules do not cause almost all code that uses
> unions to invoke UB unless one of the following is true:
>
> 1. The lvalue expression "u.i" yields something other than an
> lvalue of type "int" [though I see no basis for saying that].
>
> 2. There isn't an object with effective type "float" sharing the
> same storage [though you're arguing against that possibility].
>
> 3. A write to "u.i" doesn't access the storage associated with
> "u.f" [which would seem implausible, since it clearly *does*
> access that storage].
>
> Which of the following applies, or is there something I'm missing?
Presumably you mean "above" rather than "following" there.
What you're missing is that changing bytes of memory that
underlie an object does not necessarily constitute an access to
that particular object. When u.i is assigned, the value of u.f
is affected because its underlying memory overlaps the memory
occupied by u.i, but the u.f object is not accessed by that
assignment.
[toc] | [prev] | [next] | [standalone]
| From | Robert Wessel <robertwessel2@yahoo.com> |
|---|---|
| Date | 2017-01-31 13:36 -0600 |
| Message-ID | <7gp19c50cibbpk384r2m7dpn94bs70mj92@4ax.com> |
| In reply to | #102373 |
On Mon, 23 Jan 2017 07:04:24 -0800 (PST), supercat@casperkitty.com
wrote:
>On Friday, January 20, 2017 at 1:31:42 PM UTC-6, Keith Thompson wrote:
>> An "object" is by definition a "region of data storage in the
>> execution environment, the contents of which can represent values".
>> (I've encouraged you several times to consult this definition.)
>> s1.x and u1.x are objects. (I'm referring to the entities that
>> "s1.x" and "u1.x" refer to, not to `s1.x` and `u2.x` as expressions;
>> as expressions, both are clearly lvalues.) Do you disagree?
>
>Given "union u { uint32_t x; float y; } u;", if both u.x and u.y are objects,
>which of the following can be said about the code "u.x = 1;":
>
> 1. The thing to the left of the equals is something other than an
> lvalue of type "uint32_t".
>
> 2. The code does not access the stored value of a "float" object.
>
> 3. The code invokes Undefined Behavior because it uses an lvalue of type
> uint32_t to access the value of a float object.
>
>I would regard possibility #3 as preposterous, since it would suggest that
>any union which contained anything other than a combination of alias-
>compatible types (e.g. int32_t and uint32_t) would be completely unusable
>for any purpose.
That's silly. Unions allow you to define objects that can hold
several different types of sub-objects, without needing to allocate
storage for all of them. That's useful. You're just limited to
reading data out from the same leg of the unions as you used to write
data into the union. What the standard does not define is what
happens when you try to convert types using the internal
representation and different legs of the union for writing and
reading.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2017-01-31 12:23 -0800 |
| Message-ID | <0d657ad4-5b75-4b8d-9f52-b4302502989f@googlegroups.com> |
| In reply to | #102858 |
On Tuesday, January 31, 2017 at 1:35:38 PM UTC-6, robert...@yahoo.com wrote:
> On Mon, 23 Jan 2017 07:04:24 -0800 (PST), supercat wrote:
>
> >On Friday, January 20, 2017 at 1:31:42 PM UTC-6, Keith Thompson wrote:
> >> An "object" is by definition a "region of data storage in the
> >> execution environment, the contents of which can represent values".
> >> (I've encouraged you several times to consult this definition.)
> >> s1.x and u1.x are objects. (I'm referring to the entities that
> >> "s1.x" and "u1.x" refer to, not to `s1.x` and `u2.x` as expressions;
> >> as expressions, both are clearly lvalues.) Do you disagree?
> >
> >Given "union u { uint32_t x; float y; } u;", if both u.x and u.y are objects,
> >which of the following can be said about the code "u.x = 1;":
> >
> > 1. The thing to the left of the equals is something other than an
> > lvalue of type "uint32_t".
> >
> > 2. The code does not access the stored value of a "float" object.
> >
> > 3. The code invokes Undefined Behavior because it uses an lvalue of type
> > uint32_t to access the value of a float object.
> >
> >I would regard possibility #3 as preposterous, since it would suggest that
> >any union which contained anything other than a combination of alias-
> >compatible types (e.g. int32_t and uint32_t) would be completely unusable
> >for any purpose.
>
> That's silly. Unions allow you to define objects that can hold
> several different types of sub-objects, without needing to allocate
> storage for all of them. That's useful. You're just limited to
> reading data out from the same leg of the unions as you used to write
> data into the union. What the standard does not define is what
> happens when you try to convert types using the internal
> representation and different legs of the union for writing and
> reading.
You disagree with possibility #3. Fair enough--I don't like it either.
As far as I can tell, though, the only way for #3 to be false would be
for either #1 or #2 to be true. Either possibility would be reasonable,
but the only way either would be supportable by anything I can see in
the Standard would be if writing to u.x caused u.y not to be an object
of type "float". I would consider that perhaps tenable since u.y could
not represent a value of type "float" during the evaluation of an
expression wherein u.x was being written.
Interpreting the definition of "object" in such fashion would be stretching
things a bit, but I don't see anything else in the Standard that could
reconcile the behavior of unions with 6.5(7).
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-02-01 13:48 -0800 |
| Message-ID | <kfninotd1m3.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102858 |
Robert Wessel <robertwessel2@yahoo.com> writes: > [...] Unions allow you to define objects that can hold > several different types of sub-objects, without needing to allocate > storage for all of them. That's useful. You're just limited to > reading data out from the same leg of the unions as you used to write > data into the union. What the standard does not define is what > happens when you try to convert types using the internal > representation and different legs of the union for writing and > reading. Do you mean that the Standard doesn't define such cases completely (eg, they may depend on implementation-defined or unspecified behavior), or that it doesn't define such cases at all (ie, so doing so would constitute undefined behavior in all cases)? As I read the Standard, the behavior in such cases is completely defined, modulo knowing the required implementation-defined representations of the different types involved. (Note: assuming the member being read is completely contained in the member that was written.) Do you think otherwise? If so can you explain what passages in the Standard lead you to this conclusion?
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-01-31 08:53 -0800 |
| Message-ID | <kfn8tprdvc7.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102170 |
Keith Thompson <kst-u@mib.org> writes: > supercat@casperkitty.com writes: >> [...] > > In this context, I don't care. [...] I see no point in > bringing in irrelevant complications. Haven't you noticed? Bringing in irrelevant complications is pretty much supercat's standard MO.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@invalid.add> |
|---|---|
| Date | 2017-01-19 14:10 +0100 |
| Message-ID | <o5qdra$1r1n$1@gioia.aioe.org> |
| In reply to | #102137 |
On 1/18/2017 6:59 PM, Keith Thompson wrote:
>
> BTW, the 1974 and 1975 editions of the C Reference Manual both say:
>
> An object is a manipulatable region of storage; an lvalue is an
> expression referring to an object. An obvious example of an lvalue
> expression is an identifier.
True, but shortly after Ritchie wrote:
The name "lvalue" comes from the assignment expression "E1 = E2" in
which the left operand E1 must be an lvalue expression.
Which may be seen, strictly speaking, more an explanation of the name
than a formal definition, but nonetheless shows what he had in mind.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2017-01-30 12:05 -0800 |
| Message-ID | <kfno9yofh5b.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #102023 |
luser droog <luser.droog@gmail.com> writes: > On Friday, January 13, 2017 at 7:09:00 PM UTC-6, Tim Rentsch wrote: >> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> >>> Manfred <noname@invalid.add> writes: >>> >>>> Here the C rationale appears to be "result of expressions are rvalues" >>>> i.e. value-oriented, while the C++ rationale appears to be "result of >>>> expressions are objects" i.e. more symbol-oriented. >>> >>> I can't comment on C++'s abstract model because I have not studied the >>> standard, but, in C, expressions /evaluate/ to values (we could call >>> them rvalues but that's probably unnecessary and the standard doesn't), >>> whereas some syntactic forms of expression /are/ lvalues. So you are >>> right that there is no kind of "value" (in C's abstract semantics) that >>> could be used to denote objects. lvalues are simply expressions, not >>> values, despite the name. >>> >>> But I don't think that gets us any closer to knowing what might or might >>> not be "reasonable" in C. The C standard enumerates all the expression >>> forms that are lvalues and, as in the case of x.y for example, it >>> sometimes depends on whether one or other part of the expression is >>> itself an lvalue. So there's no obvious reason that it could not say >>> that a conditional expression is an lvalue if both arms are lvalue >>> expressions. >> >> For what it's worth (and I know it may not be much), the current >> choices in C make sense to me intuitively because I think of >> "lvalue" as meaning roughly the same thing as "address". (Note: >> in the sense of a machine address, not in the sense of C's & >> operator.) All of C's lvalue expressions identify a particular >> object, and the "lvalue" of that expression is the "address" of >> the object. Moreover there is a sense in which that is all they >> do, is to identify a single object. Compound literals might seem >> like an exception to that; I don't see them that way, probably >> because I think of a compound literal as a declarationless >> variable, and variables are of course lvalues. >> >> Seen from this perspective, a conditional expression would stand >> out because there is (potentially) more than one object, and >> there is more to the operator than just identifying an object. >> Of course conditional expressions could be used to construct >> lvalues, but that construction doesn't fit with my (admittedly >> historical) view of what "lvalue" means. >> >> To be clear, I don't mean to offer any sort of philosophical >> truth here. I am just explaining my own views and reactions, in >> case doing that might help someone form a useful mental model >> for C's current choices. > > FWIW, my conception of an lvalue is slightly different. To me it > is "a thing which can be on the left of an assignment operator". > I suppose this is more of a "functional" definition. [...] The term generally used is operational definition. IME terms that are "defined" via operational definitions are irritating and often bordering on useless, and frequently not worthy of being called a definition in the usual sense of the word. Here the proposed definition offers no help, when the point of defining the term lvalue is (among other things) to communicate just which things _can_ go on the left hand side of an assignment operator. (And not all lvalues in C are allowed on the LHS of assignment operators, but that is a side issue.)
[toc] | [prev] | [standalone]
Page 4 of 4 — ← Prev page 1 2 3 [4]
Back to top | Article view | comp.lang.c
csiph-web