Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #95500 > unrolled thread
| Started by | Andreas <nospam@invalid.invalid> |
|---|---|
| First post | 2016-11-01 13:15 +0100 |
| Last post | 2016-12-14 10:14 -0800 |
| Articles | 20 on this page of 60 — 16 participants |
Back to article view | Back to comp.lang.c
Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-01 13:15 +0100
Re: Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-01 13:34 +0100
Re: Aliasing and subtyping structs Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-01 15:27 +0000
Re: Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-02 09:47 +0100
Re: Aliasing and subtyping structs Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-02 15:47 +0000
Re: Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-08 00:24 +0100
Re: Aliasing and subtyping structs supercat@casperkitty.com - 2016-11-07 21:42 -0800
Re: Aliasing and subtyping structs <william@wilbur.25thandClement.com> - 2016-11-03 18:53 -0700
Re: Aliasing and subtyping structs supercat@casperkitty.com - 2016-11-04 09:56 -0700
Re: Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-08 21:53 +0100
Re: Aliasing and subtyping structs James Kuyper <jameskuyper@verizon.net> - 2016-11-01 11:41 -0400
Re: Aliasing and subtyping structs Andreas <nospam@invalid.invalid> - 2016-11-02 09:55 +0100
"Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2016-11-21 16:59 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-21 07:32 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "James R. Kuyper" <jameskuyper@verizon.net> - 2016-11-21 11:15 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-21 08:35 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2016-11-22 11:42 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-22 06:50 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-22 16:07 +0000
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-22 12:02 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-22 23:36 +0000
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-22 16:24 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Richard Damon <Richard@Damon-Family.org> - 2016-11-22 22:21 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-23 08:31 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] me <crisdunbar@gmail.com> - 2016-11-23 09:01 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-23 12:05 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@gmail.com> - 2016-11-22 23:23 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "James R. Kuyper" <jameskuyper@verizon.net> - 2016-11-22 16:02 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-22 14:13 -0800
Re: container_of() macro Noob <root@127.0.0.1> - 2016-11-23 01:10 +0100
Re: container_of() macro <william@wilbur.25thandClement.com> - 2016-11-22 20:10 -0800
Re: container_of() macro "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-11-23 15:10 -0800
Re: container_of() macro David Brown <david.brown@hesbynett.no> - 2016-11-23 11:31 +0100
Re: container_of() macro Anton Shepelev <anton.txt@g{oogle}mail.com> - 2016-11-23 14:07 +0300
Re: container_of() macro supercat@casperkitty.com - 2016-11-23 08:41 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@gmail.com> - 2016-11-30 00:14 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "James R. Kuyper" <jameskuyper@verizon.net> - 2016-11-29 17:23 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@gmail.com> - 2016-12-04 18:48 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "James R. Kuyper" <jameskuyper@verizon.net> - 2016-12-04 12:17 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@gmail.com> - 2016-12-04 22:15 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "James R. Kuyper" <jameskuyper@verizon.net> - 2016-12-04 15:06 -0500
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@gmail.com> - 2016-12-12 22:31 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-11-23 13:39 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] luser droog <luser.droog@gmail.com> - 2016-11-23 15:10 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-11-23 15:13 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] luser droog <luser.droog@gmail.com> - 2016-11-23 18:29 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Anton Shepelev <anton.txt@g{oogle}mail.com> - 2016-11-24 11:41 +0300
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-11-24 03:29 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-11-24 17:37 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-25 09:55 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-11-25 15:22 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-11-28 18:18 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-11-29 04:48 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-29 07:28 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-11-30 08:26 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] supercat@casperkitty.com - 2016-11-30 09:13 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-12-12 16:44 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Melzzzzz <mel@zzzzz.com> - 2016-12-13 02:18 +0100
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-12-14 09:47 -0800
Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] Thiago Adams <thiago.adams@gmail.com> - 2016-12-14 10:14 -0800
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-11-22 23:36 +0000 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <8737ijxf2e.fsf@bsb.me.uk> |
| In reply to | #97303 |
supercat@casperkitty.com writes: > On Tuesday, November 22, 2016 at 10:07:39 AM UTC-6, Ben Bacarisse wrote: >> supercat writes: >> <snip> >> > C74 >> >> What's that? Do you have a reference for it? > > Sorry--I thought you'd seen other posts where I've used the term previously > as an informal name for the language described by the 1974 C Reference > Manual. Ah, right, pre-K&R C. Not a language I'd like to go back to. From what you go on to say I don't think you do either. I sounds like you want some tailored mash-up that fits your view of what C should be. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-11-22 16:24 -0800 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <56c1752f-53c2-425e-8bd9-cb94d6efc9bb@googlegroups.com> |
| In reply to | #97319 |
On Tuesday, November 22, 2016 at 5:36:36 PM UTC-6, Ben Bacarisse wrote: > supercat writes: > Ah, right, pre-K&R C. Not a language I'd like to go back to. From what > you go on to say I don't think you do either. I sounds like you want > some tailored mash-up that fits your view of what C should be. I am of the opinion that later versions of languages should strive to be supersets of earlier versions whenever practical. If earlier features become too expensive to support by default the solution is to define a means by which programs can indicate when/whether they need support for the features in question; in some cases that may be accomplished by adding a "language-version" directive and then specifying that code which states that it is written for language version X or later must not use feature Y unless it explicitly specifies that it does so. Voila--old code continues to work as it always has, new code that doesn't need to use the features in question can be compiled with optimizations that would break older code, and code that needs the features can be marked to block optimizations in the few places they'd be problematic while allowing them everywhere else. In what way would that not be a preferable state of affairs to what exists now? For many possible behavioral guarantees, there will be some programs where they have a high cost and no benefit, and others where they have ZERO cost but significant benefit. Rather than trying to forge some horrible compromise, it would be much more helpful to simply let code *specify* which guarantees it needs. To allow for the possibility that some platforms might not be capable of supporting some guarantees, implementations would have the option to refuse compilation of code requiring them. A compiler that refuses to compile any program that requires any guarantee beyond the minimums could be conforming, but would likely be regarded as being of poor quality. What would be important would be that use of the features would never result in UB. Either they would work as expected, or compilation would fail outright. Both situation are vastly preferable to generating machine code which does not meet requirements.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2016-11-22 22:21 -0500 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <8X7Zz.63075$WD2.5011@fx35.iad> |
| In reply to | #97324 |
On 11/22/16 7:24 PM, supercat@casperkitty.com wrote: > On Tuesday, November 22, 2016 at 5:36:36 PM UTC-6, Ben Bacarisse wrote: >> supercat writes: >> Ah, right, pre-K&R C. Not a language I'd like to go back to. From what >> you go on to say I don't think you do either. I sounds like you want >> some tailored mash-up that fits your view of what C should be. > > I am of the opinion that later versions of languages should strive to be > supersets of earlier versions whenever practical. If earlier features > become too expensive to support by default the solution is to define a > means by which programs can indicate when/whether they need support for > the features in question; in some cases that may be accomplished by adding > a "language-version" directive and then specifying that code which states > that it is written for language version X or later must not use feature Y > unless it explicitly specifies that it does so. > > Voila--old code continues to work as it always has, new code that doesn't > need to use the features in question can be compiled with optimizations > that would break older code, and code that needs the features can be marked > to block optimizations in the few places they'd be problematic while > allowing them everywhere else. > > In what way would that not be a preferable state of affairs to what exists > now? For many possible behavioral guarantees, there will be some programs > where they have a high cost and no benefit, and others where they have ZERO > cost but significant benefit. Rather than trying to forge some horrible > compromise, it would be much more helpful to simply let code *specify* which > guarantees it needs. > > To allow for the possibility that some platforms might not be capable of > supporting some guarantees, implementations would have the option to > refuse compilation of code requiring them. A compiler that refuses to > compile any program that requires any guarantee beyond the minimums could > be conforming, but would likely be regarded as being of poor quality. What > would be important would be that use of the features would never result in > UB. Either they would work as expected, or compilation would fail outright. > Both situation are vastly preferable to generating machine code which does > not meet requirements. > If you look at how the Standards Committee has worked on the Standard, backwards compatibility HAS been a key point. If the Standard mandated a certain behavior for a code sequence, they try very hard to not change that, and in cases where the previous standard has left behavior undefined or implementation defined, they try hard to not mandate behavior in a way incompatible with a real existing implementation. What they haven't required is that an implementation when it becomes a new implementation (maybe implementing a new version of the standard) be backwards compatible with its previous non-standard required behavior, in part because they ARE different implementations (and in fact, most 'implementations' are really to the standard a whole lot of different implementations based on the option flags given when processing, many of which may actually be non-conforming). Most of the 'additional guarantees' that you would like to see, actually to the standard process would be great things for a supplemental standard (in the vain of POSIX), which provide limitations to the implementations and promises to the user beyond the base C standard, as an extension. The Standards Committee has been somewhat reluctant to add 'optional' features to the Standard (though it does have a few, normally for special reasons). I suspect that since what you are looking for fits so nicely as an extension, I can't see it likely for them to add a bunch of new optional features to the base Standard.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-11-23 08:31 -0800 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <08d60868-93fd-4a5e-927d-5533d701a3fe@googlegroups.com> |
| In reply to | #97326 |
On Tuesday, November 22, 2016 at 9:21:52 PM UTC-6, Richard Damon wrote:
> If you look at how the Standards Committee has worked on the Standard,
> backwards compatibility HAS been a key point. If the Standard mandated a
> certain behavior for a code sequence, they try very hard to not change
> that, and in cases where the previous standard has left behavior
> undefined or implementation defined, they try hard to not mandate
> behavior in a way incompatible with a real existing implementation.
If the C89 Standard Committee was trying to maintain backward compatibility
(I believe they were) that would imply that they did not expect that
describing formerly-defined actions as invoking "Undefined Behavior" would
break programs that relied upon them. Implementations would be free, after
all, to keep on handling those actions in useful fashion whether or not the
Standard mandated such treatment.
I think the difficulty is that the Committee's actions have been
reinterpreted as a decision to break code which used those behaviors. The
1974 document (which I think represents the best definition of what the C
language was in 1974) clearly and unambiguously defines semantics which are
sometimes useful, but are not available in the language defined by today's
Standard. At what point, if ever, was there a conscious decision to remove
them, or was there instead a progression where one version of the Standard
didn't think it necessary to mandate them since compilers universally
supported them anyway, and then a later version of the Standard was drawn
from the perspective that the language had never supported the behaviors?
> What they haven't required is that an implementation when it becomes a
> new implementation (maybe implementing a new version of the standard) be
> backwards compatible with its previous non-standard required behavior,
> in part because they ARE different implementations (and in fact, most
> 'implementations' are really to the standard a whole lot of different
> implementations based on the option flags given when processing, many of
> which may actually be non-conforming).
I think they expected that if existing implementations for machines with
some characteristic [e.g. 16-bit big-endian silent-wraparound two's-
complement, using 32-bit linear pointers] naturally supported certain
useful semantics, future implementations for similar platforms would
naturally support those same behaviors. Compilers might offer various
options to loosen up behavioral guarantees, but quality implementations
should try to make clear what guarantees would be waived by which options,
and should ensure that old semantics remain available.
For example, a compiler might treat signed integer types as being implicitly
promotable to larger types (which could be larger than any types available
to the user). Given "int i1,i2; long L1,L2;" a compiler might transform
"L1=i1*i2;" into "L1=(long)i1*i2;" or "L1+1 > L2" into "L1 >= L2", but
allow code to force wrapping semantics with "L1=(int)(i1*i2);" or
"(long)(L1+1) > L2". Note that compilers wouldn't have to reach very far
to apply the former transforms, and that the use of casts to block them is
analogous to what's required in floating-point when using platforms that
don't promise to refrain from using extra precision during computations
[e.g. given "float f=16777216.0f; double d1=f+1.0f, d2=(float)(f+1.0f);"
the value of d1 might be 16777217.0f, but d2 would be 16777216.0f].
> Most of the 'additional guarantees' that you would like to see, actually
> to the standard process would be great things for a supplemental
> standard (in the vain of POSIX), which provide limitations to the
> implementations and promises to the user beyond the base C standard, as
> an extension.
A problem I think is that people writing documentation seldom bother to
specify things which they consider obvious. How many shirt catalogs
explicitly promise that shirts have two sleeves on opposite sides?
> The Standards Committee has been somewhat reluctant to add 'optional'
> features to the Standard (though it does have a few, normally for
> special reasons). I suspect that since what you are looking for fits so
> nicely as an extension, I can't see it likely for them to add a bunch of
> new optional features to the base Standard.
For the "Standard" to really qualify as a standard, it should define classes
of things such that knowing that x is in class X and knowing that y is in
class Y will allow one to predict something useful about the interaction of
objects x and y. By that definition, the so-called C "Standard" is only
applicable to programs with constraint violations (which generally aren't
very useful).
Recognizing optional behaviors would greatly increase the value of the
Standard by making it possible and practical to define two very useful
categories of implementations and programs and a couple of useful guarantees
related to them:
If an implementation which is *at least* Minimally Conforming [satisfying
requirements somewhat looser than what the Standard presently mandates]
is fed a Selectively Conforming program, it would be required to either
run the program without UB or fail in Implementation-Defined fashion.
If an implementation which is Conforming is fed a Strictly-Conforming
program [which satisfies a couple of additional requirements beyond what
would be required under the present standard(*)] it will run the program
successfully.
(*) Among other things, for a program to be strictly conforming, it would
be required to include a directive mandating either static or run-time
stack checking, and if a program which specifies static checking uses
recursion, it would need to include directives that promise a limit
to recursive nesting. This would eliminate stack overflow as a possible
cause of UB for strictly-conforming programs.
While many tasks cannot be done by Strictly Conforming programs, and the
Standard does not provide any guarantee that even Strictly Conforming
programs will run without UB on more than one implementation, adding
optional behaviors to the Standard would make it possible to greatly expand
the range of programs to which the Standard would apply, and offer an
extremely useful guarantee about their behavior.
[toc] | [prev] | [next] | [standalone]
| From | me <crisdunbar@gmail.com> |
|---|---|
| Date | 2016-11-23 09:01 -0800 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <a6c8c092-7107-4ef0-91fd-69742b289ed8@googlegroups.com> |
| In reply to | #97349 |
On Wednesday, November 23, 2016 at 8:31:33 AM UTC-8, supe...@casperkitty.com wrote: > On Tuesday, November 22, 2016 at 9:21:52 PM UTC-6, Richard Damon wrote: > > If you look at how the Standards Committee has worked on the Standard, > > backwards compatibility HAS been a key point. If the Standard mandated a > > certain behavior for a code sequence, they try very hard to not change > > that, and in cases where the previous standard has left behavior > > undefined or implementation defined, they try hard to not mandate > > behavior in a way incompatible with a real existing implementation. > > If the C89 Standard Committee was trying to maintain backward compatibility > (I believe they were) that would imply that they did not expect that > describing formerly-defined actions as invoking "Undefined Behavior" would > break programs that relied upon them. Implementations would be free, after > all, to keep on handling those actions in useful fashion whether or not the > Standard mandated such treatment. In a very real way, _nothing_ had defined behaviour before the standard, so claiming that formerly defined behaviour changed to undefined doesn't make sense. If implementation want to maintain their previous behaviour even in the face of it now being officially "undefined", they're free to do so. > I think the difficulty is that the Committee's actions have been > reinterpreted as a decision to break code which used those behaviors. No, the standard merely describes which of those behaviours are in fact defined, and how. > The > 1974 document (which I think represents the best definition of what the C > language was in 1974) clearly and unambiguously defines semantics which are > sometimes useful, but are not available in the language defined by today's > Standard. And thank goodness. Someone else has already mentioned that you seem to want current C to be pretty much like your C74, but I'd wager a significant amount of beer that very few others here share that view. > > > What they haven't required is that an implementation when it becomes a > > new implementation (maybe implementing a new version of the standard) be > > backwards compatible with its previous non-standard required behavior, > > in part because they ARE different implementations (and in fact, most > > 'implementations' are really to the standard a whole lot of different > > implementations based on the option flags given when processing, many of > > which may actually be non-conforming). > > I think they expected that if existing implementations for machines with > some characteristic [e.g. 16-bit big-endian silent-wraparound two's- > complement, using 32-bit linear pointers] naturally supported certain > useful semantics, future implementations for similar platforms would > naturally support those same behaviors. Compilers might offer various > options to loosen up behavioral guarantees, but quality implementations > should try to make clear what guarantees would be waived by which options, > and should ensure that old semantics remain available. > > For example, a compiler might treat signed integer types as being implicitly > promotable to larger types (which could be larger than any types available > to the user). Given "int i1,i2; long L1,L2;" a compiler might transform > "L1=i1*i2;" into "L1=(long)i1*i2;" or "L1+1 > L2" into "L1 >= L2", but > allow code to force wrapping semantics with "L1=(int)(i1*i2);" or > "(long)(L1+1) > L2". Note that compilers wouldn't have to reach very far > to apply the former transforms, and that the use of casts to block them is > analogous to what's required in floating-point when using platforms that > don't promise to refrain from using extra precision during computations > [e.g. given "float f=16777216.0f; double d1=f+1.0f, d2=(float)(f+1.0f);" > the value of d1 might be 16777217.0f, but d2 would be 16777216.0f]. > > > Most of the 'additional guarantees' that you would like to see, actually > > to the standard process would be great things for a supplemental > > standard (in the vain of POSIX), which provide limitations to the > > implementations and promises to the user beyond the base C standard, as > > an extension. > > A problem I think is that people writing documentation seldom bother to > specify things which they consider obvious. How many shirt catalogs > explicitly promise that shirts have two sleeves on opposite sides? A shirt catalogue is not a standard. Standards _do_ tend to define things that are "obvious". What's interesting to me is how convoluted and wordy those definitions often are, probably because when one looks closely, it's really not so "obvious" after all. > > The Standards Committee has been somewhat reluctant to add 'optional' > > features to the Standard (though it does have a few, normally for > > special reasons). I suspect that since what you are looking for fits so > > nicely as an extension, I can't see it likely for them to add a bunch of > > new optional features to the base Standard. > > For the "Standard" to really qualify as a standard, it should define classes > of things such that knowing that x is in class X and knowing that y is in > class Y will allow one to predict something useful about the interaction of > objects x and y. Um, that's exactly what the standard _does_ do; it says "if you do /this/, you'll get /that/ result". (And, explicitly or by implication, if you do anything different you're on your own.) > By that definition, the so-called C "Standard" is only > applicable to programs with constraint violations (which generally aren't > very useful). I don't see how that follows. > Recognizing optional behaviors would greatly increase the value of the > Standard by making it possible and practical to define two very useful > categories of implementations and programs and a couple of useful guarantees > related to them: Taken to the extreme, _any_ implementation could be called conforming as long as every single way in which its behaviour differs from other implementations was documented as an option. How is this better than no standard at all?
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-11-23 12:05 -0800 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <78a021a2-d6de-4f23-977f-2ea59f230fe1@googlegroups.com> |
| In reply to | #97351 |
On Wednesday, November 23, 2016 at 11:01:18 AM UTC-6, someone wrote:
> On Wednesday, November 23, 2016 at 8:31:33 AM UTC-8, supercat wrote:
> > If the C89 Standard Committee was trying to maintain backward compatibility
> > (I believe they were) that would imply that they did not expect that
> > describing formerly-defined actions as invoking "Undefined Behavior" would
> > break programs that relied upon them. Implementations would be free, after
> > all, to keep on handling those actions in useful fashion whether or not the
> > Standard mandated such treatment.
>
> In a very real way, _nothing_ had defined behaviour before the standard,
> so claiming that formerly defined behaviour changed to undefined doesn't
> make sense. If implementation want to maintain their previous behaviour
> even in the face of it now being officially "undefined", they're free to
> do so.
Standards committees is not the only entities in the universe that
"define" things. The 1974 document specifies how a couple of particular
implementations work. Authors of other implementations were expected to
make them behave in analogous fashion as appropriate for the target
platform when practical. For target platforms that were very much like
the PDP-11, almost all behaviors could be defined as "do what the PDP-11
would do". Only when targeting platforms which were different did things
become problematic (e.g. on a PDP-11 there's no question about what (-1)<<1
should mean, but on a ones'-complement machine there would be two plausible
meanings and on a sign-magnitude machine there would be no clear meaning).
> > I think the difficulty is that the Committee's actions have been
> > reinterpreted as a decision to break code which used those behaviors.
>
> No, the standard merely describes which of those behaviours are in fact
> defined, and how.
Which of those behaviors are defined *by the Standard*. Before the Standard
was ratified, any compiler for two's-complement silent-wraparound hardware
which didn't evaluate (-1)<<1 as -2 would have been considered "broken".
Whether or not anything specifically defined the behavior of <<, the meaning
of left-shifting two's-complement values was most likely established even
before Dennis Ritchie was born [I don't know exactly when during the design
of the Atanasoff-Berry Computer the behavior of two's-complement math was
established, or if it had been established for something earlier, but it
would presumably have been established by the time work was discontinued in
1942].
I see no evidence that the authors of the Standard intended that it cause
anything whose meaning had been well established on certain kinds of
machines prior to the Standard's ratification to be regarded as less well
defined than it had been previously.
> > The
> > 1974 document (which I think represents the best definition of what the C
> > language was in 1974) clearly and unambiguously defines semantics which are
> > sometimes useful, but are not available in the language defined by today's
> > Standard.
>
> And thank goodness. Someone else has already mentioned that you seem to want
> current C to be pretty much like your C74, but I'd wager a significant
> amount of beer that very few others here share that view.
I have said that I want a language whose available semantics are a superset
of those available in C74, at least when running on platforms which share
some basic architectural features with the PDP-11 (storage consists of a
plurality of linearly-addressable octets, each integer type larger than
char is stored as two half-size chunks without padding, integer math is
performed using two's-complement hardware without overflow traps, etc.).
I wouldn't mind having to explicitly request semantics which aren't always
needed *if* there were a concise way of doing so which could be expected
to work on platforms which would naturally support the behaviors in
question. The problem is that in many situations where when the easiest
way for compilers to support such operations on platforms where they would
be practical would be to simply treat them as defined whether the Standard
required it or not, nobody saw any need to specify any alternative which
would be unambiguously defined on all platforms that supported it.
> A shirt catalogue is not a standard. Standards _do_ tend to define things
> that are "obvious". What's interesting to me is how convoluted and wordy
> those definitions often are, probably because when one looks closely, it's
> really not so "obvious" after all.
The analogous "standard" would be the fact that shirts intended for use
by normal humans will have two sleeves, one on each side. Many standards
do go out of their way to state the obvious, but the C89 Standard went
out of its way to avoid avoiding suggesting that any particular
implementation should be considered inferior to others, even when that
meant refraining from recommending things that almost all implementations
should support when practical, but which a few implementations might be
able to.
Most modern standards make use of terms MUST, SHOULD, etc. as defined in
RFC-2119. In many cases, a lot of the value of a Standard comes not from
the MUST items, but from the SHOULD items. A standard written by someone
who wants to avoid SHOULD items will often be inferior to one written by
someone who embraces them.
> > For the "Standard" to really qualify as a standard, it should define classes
> > of things such that knowing that x is in class X and knowing that y is in
> > class Y will allow one to predict something useful about the interaction of
> > objects x and y.
>
> Um, that's exactly what the standard _does_ do; it says "if you do /this/,
> you'll get /that/ result". (And, explicitly or by implication, if you do
> anything different you're on your own.)
The Standard requires that for every conforming implementation, there must
be at least one program meeting certain criteria that the implementation
will process as described by the Standard. Nothing in the Standard would
forbid an implementation from dying with a stack overflow (and behaving
in arbitrary fashion) when fed any other program.
> > By that definition, the so-called C "Standard" is only
> > applicable to programs with constraint violations (which generally aren't
> > very useful).
>
> I don't see how that follows.
See above.
> > Recognizing optional behaviors would greatly increase the value of the
> > Standard by making it possible and practical to define two very useful
> > categories of implementations and programs and a couple of useful guarantees
> > related to them:
>
> Taken to the extreme, _any_ implementation could be called conforming as long
> as every single way in which its behaviour differs from other implementations
> was documented as an option. How is this better than no standard at all?
Under my proposed rules, feeding any Selectively Conforming program to an
implementation that was at least Minimally Conforming would result in one of
two things happening:
1. The program would function successfully.
2. The program would fail in Implementation-Defined fashion (depending
upon the directives it uses, such failure might be guaranteed to occur
at compile time, or could be deferred until run time).
A program which relies upon features which some implementations support and
others do not would be less portable than one which does not rely upon such
features, but depending upon how common the feature was it could be, for
all practical purposes, "almost" as portable. An implementation which does
not support features that are needed by many programs could be viewed as
inferior to one which does support them, but could still be very useful for
running programs that don't need such features.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2016-11-22 23:23 +0300 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <20161122232309.40aa1289366c35d048c594f3@gmail.com> |
| In reply to | #97211 |
James R. Kuyper to Anton Shepelev:
> > Am I right in thinking that "Object-oriented
> > programming in C":
> >
> > http://www.cs.rit.edu/~ats/books/ooc.pdf
> >
> > is based entirely on the violation of strict
> > aliasing?
>
> I don't have time to read that entire document
> right now. Could you cite a particular page that
> involves such violations? I know that the general
> concept of "object-oriented programming in C" (as
> opposed to the book of that title) does not rely
> violation of C's aliasing rules.
The author makes extensive use of casting between
non-aliasing pointers. He writes:
1. Passing a circle as a point means converting
from a struct Circle * to a struct Point *.
We will refer to this as an up-cast from a
subclass to a superclass -- in ANSI-C it can
only be accomplished with an explicit conver-
sion operator or through intermediate void *
values.
2. It is usually unsound, however, to pass a
point to a function intended for circles such
as Circle_draw(): converting from a struct
Point * to a struct Circle * is only permissi-
ble if the point originally was a circle. We
will refer to this as a down-cast from a su-
perclass to a subclass -- this requires ex-
plicit conversions or void * values, too, and
it can only be done to pointers to objects
that were in the subclass to begin with.
3. #define x(p) (((const struct Point *)(p)) -> x)
#define y(p) (((const struct Point *)(p)) -> y)
These macros can be applied to a pointer to
any object that starts with a struct Point,
i.e., to objects from any subclass of our
points. The technique is to up-cast the
pointer into our superclass and reference the
interesting component there. const in the
cast blocks assignments to the result. If
const were omitted
#define x(p) (((struct Point *)(p)) -> x)
a macro call x(p) produces an l-value which
can be the target of an assignment. A better
modification function would be the macro defi-
nition
#define set_x(p,v) (((struct Point *)(p)) -> x = (v))
which produces an assignment.
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2016-11-22 16:02 -0500 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <2985f44b-b799-f6bb-142e-f2c1eb9d7ee2@verizon.net> |
| In reply to | #97308 |
On 11/22/2016 03:23 PM, Anton Shepelev wrote:
> James R. Kuyper to Anton Shepelev:
>
>>> Am I right in thinking that "Object-oriented
>>> programming in C":
>>>
>>> http://www.cs.rit.edu/~ats/books/ooc.pdf
>>>
>>> is based entirely on the violation of strict
>>> aliasing?
>>
>> I don't have time to read that entire document
>> right now. Could you cite a particular page that
>> involves such violations? I know that the general
>> concept of "object-oriented programming in C" (as
>> opposed to the book of that title) does not rely
>> violation of C's aliasing rules.
>
> The author makes extensive use of casting between
> non-aliasing pointers. He writes:
>
> 1. Passing a circle as a point means converting
> from a struct Circle * to a struct Point *.
> We will refer to this as an up-cast from a
> subclass to a superclass -- in ANSI-C it can
> only be accomplished with an explicit conver-
> sion operator or through intermediate void *
> values.
On page 34, he writes:
struct Circle { const struct Point _; int rad; };
Given
struct Circle c, *pc=&c;
struct Point p, *pp=&p;
The explicit conversion he referred to is (const struct Point *)pc, and
it is allowed by 6.7.2.1p15. However, he's wrong about void* being the
only other way to do this. &pc->_ is simpler and equivalent, and will
continue to work even if some other field becomes the first member of
struct Circle.
> 2. It is usually unsound, however, to pass a
> point to a function intended for circles such
> as Circle_draw(): converting from a struct
> Point * to a struct Circle * is only permissi-
> ble if the point originally was a circle. We
In other words, given
pp = &c._;
then (struct Circle*)pp is also allowed by 6.7.2.1p15. However, given:
pp - &p;
then (struct Circle*)pp would not be allowed.
I don't see any problem with this approach. What are your concerns about it?
> will refer to this as a down-cast from a su-
> perclass to a subclass -- this requires ex-
> plicit conversions or void * values, too, and
> it can only be done to pointers to objects
> that were in the subclass to begin with.
>
> 3. #define x(p) (((const struct Point *)(p)) -> x)
> #define y(p) (((const struct Point *)(p)) -> y)
>
> These macros can be applied to a pointer to
> any object that starts with a struct Point,
> i.e., to objects from any subclass of our
> points. The technique is to up-cast the
> pointer into our superclass and reference the
> interesting component there. const in the
> cast blocks assignments to the result. If
> const were omitted
>
> #define x(p) (((struct Point *)(p)) -> x)
>
> a macro call x(p) produces an l-value which
> can be the target of an assignment. A better
> modification function would be the macro defi-
> nition
>
> #define set_x(p,v) (((struct Point *)(p)) -> x = (v))
>
> which produces an assignment.
>
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-11-22 14:13 -0800 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <df44fbed-7584-4154-956d-cb2bdc20da2c@googlegroups.com> |
| In reply to | #97310 |
On Tuesday, November 22, 2016 at 3:02:56 PM UTC-6, James R. Kuyper wrote: > The explicit conversion he referred to is (const struct Point *)pc, and > it is allowed by 6.7.2.1p15. However, he's wrong about void* being the > only other way to do this. &pc->_ is simpler and equivalent, and will > continue to work even if some other field becomes the first member of > struct Circle. ... > In other words, given > > pp = &c._; > > then (struct Circle*)pp is also allowed by 6.7.2.1p15. However, given: > > pp - &p; > > then (struct Circle*)pp would not be allowed. > > I don't see any problem with this approach. What are your concerns about it? Do you mean pp = &p for the second one? The ability to take a convert a pointer to the contained "parent" object into a pointer to the derived object is reliant upon the parent object being the first field of the object in question; if the parent gets moved to some other spot in the structure, code may still compile but it won't work. Many compilers require that code with a derived-type pointer that wants to access fields of the parent must explicitly perform the object through the parent (e.g. if "foo" is derived from "moo", and starts with a member "parent" of type "moo", then code wanting to access an "inherited" field x of object *y must write foo->parent.x rather than just foo->x, even in cases where the code in question shouldn't need to care about which members are in the original or derived class. If the length of the common portion isn't a multiple of its alignment requirement it will be necessary to add padding which can't be used by derived types. This wastes space and may also make it impossible for the structures to have layouts that match other APIs.
[toc] | [prev] | [next] | [standalone]
| From | Noob <root@127.0.0.1> |
|---|---|
| Date | 2016-11-23 01:10 +0100 |
| Subject | Re: container_of() macro |
| Message-ID | <o12mo3$2p5$1@dont-email.me> |
| In reply to | #97315 |
On 22/11/2016 23:13, supercat@casperkitty.com wrote:
> The ability to take a convert a pointer to the contained "parent" object
> into a pointer to the derived object is reliant upon the parent object being
> the first field of the object in question; if the parent gets moved to some
> other spot in the structure, code may still compile but it won't work.
Behold Linux's container_of() macro.
(110% dependent on GCC ID behavior)
http://lxr.free-electrons.com/source/include/linux/kernel.h#L830
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
[toc] | [prev] | [next] | [standalone]
| From | <william@wilbur.25thandClement.com> |
|---|---|
| Date | 2016-11-22 20:10 -0800 |
| Subject | Re: container_of() macro |
| Message-ID | <tdhfgd-q7n.ln1@wilbur.25thandClement.com> |
| In reply to | #97323 |
Noob <root@127.0.0.1> wrote:
> On 22/11/2016 23:13, supercat@casperkitty.com wrote:
>
>> The ability to take a convert a pointer to the contained "parent" object
>> into a pointer to the derived object is reliant upon the parent object being
>> the first field of the object in question; if the parent gets moved to some
>> other spot in the structure, code may still compile but it won't work.
>
> Behold Linux's container_of() macro.
> (110% dependent on GCC ID behavior)
>
> http://lxr.free-electrons.com/source/include/linux/kernel.h#L830
>
> #define container_of(ptr, type, member) ({ \
> const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> (type *)( (char *)__mptr - offsetof(type,member) );})
>
AFAICT the use of typeof (and thus also the statement expression) seems to
only serve a type safety function. I don't see why the following isn't
semantically equivalent for otherwise correct code.
(type *)((char *)(ptr) - offsetof(type, member))
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <invalid@invalid.invalid> |
|---|---|
| Date | 2016-11-23 15:10 -0800 |
| Subject | Re: container_of() macro |
| Message-ID | <o157ip$k6u$1@dont-email.me> |
| In reply to | #97329 |
On 11/22/2016 8:10 PM, william@wilbur.25thandClement.com wrote:
> Noob <root@127.0.0.1> wrote:
>> On 22/11/2016 23:13, supercat@casperkitty.com wrote:
>>
>>> The ability to take a convert a pointer to the contained "parent" object
>>> into a pointer to the derived object is reliant upon the parent object being
>>> the first field of the object in question; if the parent gets moved to some
>>> other spot in the structure, code may still compile but it won't work.
>>
>> Behold Linux's container_of() macro.
>> (110% dependent on GCC ID behavior)
>>
>> http://lxr.free-electrons.com/source/include/linux/kernel.h#L830
>>
>> #define container_of(ptr, type, member) ({ \
>> const typeof( ((type *)0)->member ) *__mptr = (ptr); \
>> (type *)( (char *)__mptr - offsetof(type,member) );})
>>
>
> AFAICT the use of typeof (and thus also the statement expression) seems to
> only serve a type safety function. I don't see why the following isn't
> semantically equivalent for otherwise correct code.
>
> (type *)((char *)(ptr) - offsetof(type, member))
>
Looks okay to me.
FWIW, check this out wrt offsetof:
_________________________________________________
#define ALIGN_OF(mp_type) \
offsetof( \
struct \
{ \
char pad_ALIGN_OF; \
mp_type type_ALIGN_OF; \
}, \
type_ALIGN_OF \
)
_________________________________________________
I posted in this thread:
https://groups.google.com/d/topic/comp.lang.c.moderated/dfFaOdBRq-0/discussion
;^)
Also, wrt container_of, here is some quick code I just typed out:
_________________________________________________
#include <stdio.h>
#include <stddef.h>
struct foo
{
int a;
};
struct contain
{
char a;
double b;
struct foo c;
char d;
};
#define CONTAINS(mp_ptr, mp_type, mp_member) \
((mp_type*)(((unsigned char*)(mp_ptr)) - \
offsetof(mp_type, mp_member)))
int main(void)
{
struct contain c = { 'A', -.66, { 67 }, 'D' };
struct foo* bp = &c.c;
struct contain* cp = CONTAINS(bp, struct contain, c);
printf("struct contain:(%p)->c(%c, %f, %d, %c)\n",
(void*)&c, c.a, c.b, c.c.a, c.d);
printf("struct foo:(%p)->bp(%d)\n",
(void*)bp, bp->a);
printf("struct contain:(%p)->cp(%c, %f, %d, %c)\n",
(void*)cp, cp->a, cp->b, cp->c.a, cp->d);
return 0;
}
_________________________________________________
Quite a useful construct. I have been taking advantage of it for a while
now.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-11-23 11:31 +0100 |
| Subject | Re: container_of() macro |
| Message-ID | <o13r51$caa$1@dont-email.me> |
| In reply to | #97323 |
On 23/11/16 01:10, Noob wrote:
> On 22/11/2016 23:13, supercat@casperkitty.com wrote:
>
>> The ability to take a convert a pointer to the contained "parent" object
>> into a pointer to the derived object is reliant upon the parent object being
>> the first field of the object in question; if the parent gets moved to some
>> other spot in the structure, code may still compile but it won't work.
>
> Behold Linux's container_of() macro.
> (110% dependent on GCC ID behavior)
>
> http://lxr.free-electrons.com/source/include/linux/kernel.h#L830
>
> #define container_of(ptr, type, member) ({ \
> const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> (type *)( (char *)__mptr - offsetof(type,member) );})
>
Just as a note here, the Linux kernel is always compiled with
-fno-strict-alias. So there is no problem if code does not follow the C
rules about which types are compatible regarding aliasing.
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@g{oogle}mail.com> |
|---|---|
| Date | 2016-11-23 14:07 +0300 |
| Subject | Re: container_of() macro |
| Message-ID | <20161123140759.1dfea18fcb556a524ab6b9b7@g{oogle}mail.com> |
| In reply to | #97337 |
David Brown: >Just as a note here, the Linux kernel is always >compiled with -fno-strict-alias. So there is no >problem if code does not follow the C rules about >which types are compatible regarding aliasing. And here Linus's opinion about it: http://stackoverflow.com/a/2959468/2862241 The second post in full is here: http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg01647.html See also the comments to the StackOverflow post about the way gcc follows the letter rather than the spirit of the standard. -- () ascii ribbon campaign - against html e-mail /\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-11-23 08:41 -0800 |
| Subject | Re: container_of() macro |
| Message-ID | <692e9c17-0d2f-47da-ab4a-082bd90a79f8@googlegroups.com> |
| In reply to | #97337 |
On Wednesday, November 23, 2016 at 4:31:42 AM UTC-6, David Brown wrote: > Just as a note here, the Linux kernel is always compiled with > -fno-strict-alias. So there is no problem if code does not follow the C > rules about which types are compatible regarding aliasing. The authors of gcc have stated that they feel no obligation to uphold behaviors which are not documented and are not mandated by the Standard, no matter how consistently the compiler has upheld them in the past. Does anything in gcc's documentation actually promise that -fno-strict-alias will cause it to always and forever regard aliasing as defined behavior, rather than merely disabling *today's* optimizations that would break such code but not precluding the possibility of imposing future optimizations which would break it? If the authors of gcc had not explicitly expressed the indicated attitude when responding to bug reports, I would be satisfied that the only sensible purpose of -fno-strict-alias would be to cause aliasing to be treated as having defined behavior, but if the authors of the Standard want to reserve the right to change any behavior that isn't explicitly documented, then failure to explicitly document any behavior should be taken as reserving the right to break code that uses it. BTW, are there any versions of Unix that do not rely upon forms of aliasing not mandated by the C or Posix standards?
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2016-11-30 00:14 +0300 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <20161130001448.0acf489caa3aa31becdd5e2c@gmail.com> |
| In reply to | #97310 |
James R. Kuyper to Anton Shepelev:
> > The author makes extensive use if casting be-
> > tween non-aliasing pointers. He author writes:
> >
> > 1. Passing a circle as a point means convert-
> > ing from a struct Circle * to a
> > struct Point *. We will refer to this as
> > an up-cast from a subclass to a super-
> > class -- in ANSI-C it can only be accom-
> > plished with an explicit conversion opera-
> > tor or through intermediate void * values.
> >
> On page 34, he writes:
> struct Circle { const struct Point _; int rad; };
>
> Given
>
> struct Circle c, *pc=&c;
> struct Point p, *pp=&p;
>
> The explicit conversion he referred to is
> (const struct Point *)pc ,
> and it is allowed by 6.7.2.1p15.
Is it the item saying that a pointer suitably con-
verted shall point the first field of a struct? I
am sorry I have no standard at hand.
> However, he's wrong about void* being the only
> other way to do this. &pc->_ is simpler and equiv-
> alent, and will continue to work even if some oth-
> er field becomes the first member of struct Cir-
> cle.
In OOP this method is out of the question, because a
member should be accessible immediately from the ob-
ject at hand, without knowing the inheritance level
at which it has been introduced. Whereas the ->_ in
your example betrays the object's internal structure
and the assumption that it is derived from Point.
What should you do if there were a three-tier hier-
archy -- ->_->_? For aught I know, this is allowed
under the hood but not in user code.
> > 2. It is usually unsound, however, to pass a
> > point to a function intended for circles
> > such as Circle_draw(): converting from a
> > struct Point * to a struct Circle * is on-
> > ly permissible if the point originally was
> > a circle. We will refer to this as a
> > down-cast from a superclass to a sub-
> > class -- this requires explicit conver-
> > sions or void * values, too, and it can
> > only be done to pointers to objects that
> > were in the subclass to begin with.
> >
> In other words, given
>
> pp = &c._;
>
> then (struct Circle*)pp is also allowed by
> 6.7.2.1p15. However, given:
>
> pp - &p;
>
> then (struct Circle*)pp would not be allowed.
>
> I don't see any problem with this approach. What
> are your concerns about it?
The problem is that the author uses the latter ex-
pression. In the appendix "ANSI-C Programming
Hints" he shows stark innocence of the aliasing lim-
itations:
The first component of a structure starts right
at the beginning of the structure; therefore,
structures can be lengthened or shortened:
struct a { int x; };
struct c { struct a a; ... } c, * cp = & c;
struct a * ap = & c.a;
ANSI-C permits neither implicit conversions of
pointers to different structures nor direct
access to the components of an inner structure:
cp -> a.x ok, fully specified
((struct a *) cp) -> x ok, explicit conversion (!!!)
Or am missing something?
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2016-11-29 17:23 -0500 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <67f7b425-b642-398d-409b-0e767fc1ebcf@verizon.net> |
| In reply to | #97747 |
On 11/29/2016 04:14 PM, Anton Shepelev wrote:
> James R. Kuyper to Anton Shepelev:
>
>>> The author makes extensive use if casting be-
>>> tween non-aliasing pointers. He author writes:
>>>
>>> 1. Passing a circle as a point means convert-
>>> ing from a struct Circle * to a
>>> struct Point *. We will refer to this as
>>> an up-cast from a subclass to a super-
>>> class -- in ANSI-C it can only be accom-
>>> plished with an explicit conversion opera-
>>> tor or through intermediate void * values.
>>>
>> On page 34, he writes:
>> struct Circle { const struct Point _; int rad; };
>>
>> Given
>>
>> struct Circle c, *pc=&c;
>> struct Point p, *pp=&p;
>>
>> The explicit conversion he referred to is
>> (const struct Point *)pc ,
>> and it is allowed by 6.7.2.1p15.
>
> Is it the item saying that a pointer suitably con-
> verted shall point the first field of a struct?
Yes.
>> However, he's wrong about void* being the only
>> other way to do this. &pc->_ is simpler and equiv-
>> alent, and will continue to work even if some oth-
>> er field becomes the first member of struct Cir-
>> cle.
>
> In OOP this method is out of the question, because a
> member should be accessible immediately from the ob-
> ject at hand, without knowing the inheritance level
> at which it has been introduced. Whereas the ->_ in
> your example betrays the object's internal structure
> and the assumption that it is derived from Point.
The cast makes the assumption that the first actual member of struct
Circle is an object of type struct Point, or an array of struct Point -
either directly, or recursively because the first member has a struct
type of which that is true.
The use of ->_, on the other hand, makes the assumption that there is
some member of struct Circle, not necessarily the first one, with a name
of _ and type of struct Point.
Is making an assumption about the location of the struct Point member
any better, or any worse, than making an assumption about the name of
that member? That depends entirely upon which assumption is more likely
to be true. If you're certain that one assumption is valid, and are
worried that the other one might not be, you should use the expression
which relies upon the assumption your certain of. Otherwise, it doesn't
matter.
> What should you do if there were a three-tier hier-
> archy -- ->_->_? For aught I know, this is allowed
> under the hood but not in user code.
>
>>> 2. It is usually unsound, however, to pass a
>>> point to a function intended for circles
>>> such as Circle_draw(): converting from a
>>> struct Point * to a struct Circle * is on-
>>> ly permissible if the point originally was
>>> a circle. We will refer to this as a
>>> down-cast from a superclass to a sub-
>>> class -- this requires explicit conver-
>>> sions or void * values, too, and it can
>>> only be done to pointers to objects that
>>> were in the subclass to begin with.
>>>
>> In other words, given
>>
>> pp = &c._;
>>
>> then (struct Circle*)pp is also allowed by
>> 6.7.2.1p15. However, given:
>>
>> pp - &p;
Correction: that should have been
pp = &p;
>> then (struct Circle*)pp would not be allowed.
>>
>> I don't see any problem with this approach. What
>> are your concerns about it?
>
> The problem is that the author uses the latter ex-
> pression. ...
I don't see any expression corresponding to that one in the code below:
> ... In the appendix "ANSI-C Programming
> Hints" he shows stark innocence of the aliasing lim-
> itations:
>
> The first component of a structure starts right
> at the beginning of the structure; therefore,
> structures can be lengthened or shortened:
>
> struct a { int x; };
> struct c { struct a a; ... } c, * cp = & c;
> struct a * ap = & c.a;
The code that I said above would not be allowed would be analogous to
the following:
struct a a;
ap = &a;
(struct c*)ap
There is no such code in the sample you've given me, and no indications
about whether or not the author is aware that such code would be
problematic.
> ANSI-C permits neither implicit conversions of
> pointers to different structures nor direct
> access to the components of an inner structure:
>
> cp -> a.x ok, fully specified
> ((struct a *) cp) -> x ok, explicit conversion (!!!)
>
> Or am missing something?
Possibly. Or maybe I'm missing something. I don't see any aliasing
problems in the above code. Could you please identify them?
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2016-12-04 18:48 +0300 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <20161204184801.3873269617033a53467cd5e1@gmail.com> |
| In reply to | #97754 |
James R. Kuyper to Anton Shepelev:
> > > On page 34, he writes:
> > > struct Circle { const struct Point _; int rad;
> > > };
> > >
> > > Given
> > >
> > > struct Circle c, *pc=&c;
> > > struct Point p, *pp=&p;
> > >
> > > The explicit conversion he referred to is
> > > (const struct Point *)pc ,
> > > and it is allowed by 6.7.2.1p15.
> > >
> > > However, he's wrong about void* being the only
> > > other way to do this. &pc->_ is simpler and
> > > equivalent, and will continue to work even if
> > > some other field becomes the first member of
> > > struct Circle.
> >
> > In OOP this method is out of the question, be-
> > cause a member should be accessible immediately
> > from the object at hand, without knowing the in-
> > heritance level at which it has been introduced.
> > Whereas the ->_ in your example betrays the ob-
> > ject's internal structure and the assumption
> > that it is derived from Point. What should you
> > do if there were a three-tier hierar-
> > chy -- ->_->_? For aught I know, this is al-
> > lowed under the hood but in user code...
>
> The cast makes the assumption that the first actu-
> al member of struct Circle is an object of type
> struct Point, or an array of struct Point -- ei-
> ther directly, or recursively because the first
> member has a struct type of which that is true.
> The use of ->_, on the other hand, makes the as-
> sumption that there is some member of struct Cir-
> cle, not necessarily the first one, with a name of
> _ and type of struct Point.
Right.
> Is making an assumption about the location of the
> struct Point member any better, or any worse, than
> making an assumption about the name of that mem-
> ber? That depends entirely upon which assumption
> is more likely to be true.
I should rather say, on one's chosen design, because
mixing both way of access it likely a bad idea any-
way, and code should be stuctured to guarantee the
correctness of one of them.
> If you're certain that one assumption is valid,
> and are worried that the other one might not be,
> you should use the expression which relies upon
> the assumption your certain of. Otherwise, it
> doesn't matter.
It's not what I am worried about. Rather, I doubt
that the by-member access agrees with the concept of
OOP's hierarchical data structures, where the mem-
bers are accessed in a uniform way indifferently of
the object's line of ascent. For example, the syn-
tax for accessing the coordinates of a Circle shall
not depend on the way Circle is derived, e.g.:
Object => Circle
(coordinates defined in the Cirlce)
Object => Point => Circle
(coordinates defined in Point)
Object => RadialFigure => Point => Circle
(coordinates defined in RadialFigure)
If that rule be violated, changing the implementa-
tion of Circle may break the code that uses it.
> > In the appendix "ANSI-C Programming Hints" he
> > shows stark innocence of the aliasing limita-
> > tions:
> >
> > The first component of a structure starts
> > right at the beginning of the structure;
> > therefore, structures can be lengthened or
> > shortened:
> >
> > struct a { int x; };
> > struct c { struct a a; ... } c, * cp = & c;
> > struct a * ap = & c.a;
> >
> > ANSI-C permits neither implicit conversions
> > of pointers to different structures nor
> > direct access to the components of an inner
> > structure:
> >
> > cp -> a.x ok, fully specified
> > ((struct a *) cp) -> x ok, explicit conversion (!!!)
> >
> >
> > Or am missing something?
>
> Possibly. Or maybe I'm missing something. I
> don't see any aliasing problems in the above code.
> Could you please identify them?
Ok. My initial concern was about aliasing, but
since conversion here is made in-place, it cannot be
a problem, because there is no second pointer vari-
able pointing to the same address. Would this:
ap = (struct a *) cp; /* alias to cp */
ap -> x = 10;
be wrong?
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2016-12-04 12:17 -0500 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <a9018b26-bafa-76d3-6fa0-a5d9e64a25b6@verizon.net> |
| In reply to | #97980 |
On 12/04/2016 10:48 AM, Anton Shepelev wrote:
> James R. Kuyper to Anton Shepelev:
...
>> If you're certain that one assumption is valid,
>> and are worried that the other one might not be,
>> you should use the expression which relies upon
>> the assumption you're certain of. Otherwise, it
>> doesn't matter.
>
> It's not what I am worried about. Rather, I doubt
> that the by-member access agrees with the concept of
> OOP's hierarchical data structures, where the mem-
> bers are accessed in a uniform way indifferently of
> the object's line of ascent. For example, the syn-
> tax for accessing the coordinates of a Circle shall
> not depend on the way Circle is derived, e.g.:
>
> Object => Circle
> (coordinates defined in the Cirlce)
>
> Object => Point => Circle
> (coordinates defined in Point)
>
> Object => RadialFigure => Point => Circle
> (coordinates defined in RadialFigure)
>
> If that rule be violated, changing the implementa-
> tion of Circle may break the code that uses it.
You're talking about a convention used for writing object-oriented C
code; code that conforms to that convention should always use the access
method that is guaranteed, by use that convention, to work.
I was giving the more general rule: C code doesn't have to follow that
convention, and if it doesn't, accessing the member by name might work
in situations where the cast wouldn't work.
>>> In the appendix "ANSI-C Programming Hints" he
>>> shows stark innocence of the aliasing limita-
>>> tions:
>>>
>>> The first component of a structure starts
>>> right at the beginning of the structure;
>>> therefore, structures can be lengthened or
>>> shortened:
>>>
>>> struct a { int x; };
>>> struct c { struct a a; ... } c, * cp = & c;
>>> struct a * ap = & c.a;
>>>
>>> ANSI-C permits neither implicit conversions
>>> of pointers to different structures nor
>>> direct access to the components of an inner
>>> structure:
>>>
>>> cp -> a.x ok, fully specified
>>> ((struct a *) cp) -> x ok, explicit conversion (!!!)
>>>
>>>
>>> Or am missing something?
>>
>> Possibly. Or maybe I'm missing something. I
>> don't see any aliasing problems in the above code.
>> Could you please identify them?
>
> Ok. My initial concern was about aliasing, but
> since conversion here is made in-place, it cannot be
> a problem, because there is no second pointer vari-
> able pointing to the same address. Would this:
>
> ap = (struct a *) cp; /* alias to cp */
> ap -> x = 10;
>
> be wrong?
No, because the result of that conversion is a pointer which is defined
as pointing at cp.a. That is an object with the declared type "struct
a", which is therefore also it's effective type. Since the effective
type of the object exactly matches the type of the lvalue that is used
to access it, it is covered by the first item in 6.5p7: "a type
compatible with the effective type of the object". "Two types have
compatible type if their types are the same." (6.2.7p1)
[toc] | [prev] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@gmail.com> |
|---|---|
| Date | 2016-12-04 22:15 +0300 |
| Subject | Re: "Object-oriented programming in C" [was: Re: Aliasing and subtyping structs] |
| Message-ID | <20161204221522.6297bf104191167f11cc0bbd@gmail.com> |
| In reply to | #97987 |
Given the code:
struct a { int x; };
struct c { struct a a; ... } c, * cp = & c;
struct a * ap = & c.a;
James R. Kuyper to Anton Shepelev:
> > Would this:
> >
> > ap = (struct a *) cp; /* alias to cp */
> > ap -> x
> >
> > be wrong?
>
> No, because the result of that conversion is a
> pointer which is defined as pointing at cp.a.
> That is an object with the declared type "struct
> a", which is therefore also it's effective type.
> Since the effective type of the object exactly
> matches the type of the lvalue that is used to ac-
> cess it, it is covered by the first item in 6.5p7:
> "a type compatible with the effective type of the
> object". "Two types have compatible type if their
> types are the same." (6.2.7p1)
Thanks. If the first field of a stucture has the
same type as that of the pointer target then pointer
conversion works. Will I violate aliasing if I re-
place cp with &c, i.e.:
cp = &c;
ap = (struct a *)&c; /* alias to cp */
ap -> x
?
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | comp.lang.c
csiph-web