Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #128138 > unrolled thread
| Started by | pozz <pozzugno@gmail.com> |
|---|---|
| First post | 2018-03-21 11:19 +0100 |
| Last post | 2018-03-21 21:39 +0000 |
| Articles | 15 — 9 participants |
Back to article view | Back to comp.lang.c
Does simple inheritance break strict-aliasing rule pozz <pozzugno@gmail.com> - 2018-03-21 11:19 +0100
Re: Does simple inheritance break strict-aliasing rule Thiago Adams <thiago.adams@gmail.com> - 2018-03-21 05:37 -0700
Re: Does simple inheritance break strict-aliasing rule Steven Petruzzellis <frelwizzen@gmail.com> - 2018-03-21 07:02 -0700
Re: Does simple inheritance break strict-aliasing rule James Kuyper <jameskuyper@verizon.net> - 2018-03-21 10:31 -0400
Re: Does simple inheritance break strict-aliasing rule supercat@casperkitty.com - 2018-03-21 09:38 -0700
Re: Does simple inheritance break strict-aliasing rule Nick Bowler <nbowler@draconx.ca> - 2018-03-21 14:46 +0000
Re: Does simple inheritance break strict-aliasing rule supercat@casperkitty.com - 2018-03-21 08:18 -0700
Re: Does simple inheritance break strict-aliasing rule Steven Petruzzellis <frelwizzen@gmail.com> - 2018-03-21 23:23 -0700
Re: Does simple inheritance break strict-aliasing rule Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-03-21 15:53 +0000
Re: Does simple inheritance break strict-aliasing rule supercat@casperkitty.com - 2018-03-21 09:30 -0700
Re: Does simple inheritance break strict-aliasing rule Keith Thompson <kst-u@mib.org> - 2018-03-21 10:20 -0700
Re: Does simple inheritance break strict-aliasing rule supercat@casperkitty.com - 2018-03-21 10:54 -0700
Re: Does simple inheritance break strict-aliasing rule Keith Thompson <kst-u@mib.org> - 2018-03-21 11:48 -0700
Re: Does simple inheritance break strict-aliasing rule supercat@casperkitty.com - 2018-03-21 14:28 -0700
Re: Does simple inheritance break strict-aliasing rule Jorgen Grahn <grahn+nntp@snipabacken.se> - 2018-03-21 21:39 +0000
| From | pozz <pozzugno@gmail.com> |
|---|---|
| Date | 2018-03-21 11:19 +0100 |
| Subject | Does simple inheritance break strict-aliasing rule |
| Message-ID | <p8tbjk$mku$1@dont-email.me> |
I'm trying to understand strict-aliasing rule, that is an assumption
that lets the compiler to better optimize the compilation process.
If the strict-aliasing rule is disabled (maybe through
-fno-strict-aliasing in gcc) the compiler can't assume the rule is valid
and it can't optimize certain object accesses.
In other words, if I don't want to break the rule, I can't access one
object through a pointer to another object (even with casting):
struct s1 *s1p;
struct s2 *s2p = (struct s2 *)s1p;
With -Wall (or -fstrict-aliasing) compiler gives a warning (and maybe
the behaviour is undefined). With -fno-strict-aliasing, the warning
disappears, the application always works but with an efficiency penalty.
Now what about inheritance? I know it is possible to simulate the
inheritance of OOP in C by defining the subclass as a structure with the
first member as the superclass.
typedef struct {
int type;
int color;
} Shape;
typedef struct {
struct Shape super;
int x1, x2, y1, y2;
} Rect;
So I can have a pointer to Shape or Rect by casting:
Rect *r;
Shape *s = (Shape *)r;
Shape *s;
if (s->type == RECT)
{
Rect *r;
r = (Rect *)s;
}
However I think I'm breaking strict-aliasing rule, don't I?
[toc] | [next] | [standalone]
| From | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| Date | 2018-03-21 05:37 -0700 |
| Message-ID | <d8069cda-f13b-4a15-a697-1b29b6dbc146@googlegroups.com> |
| In reply to | #128138 |
On Wednesday, March 21, 2018 at 7:19:43 AM UTC-3, pozz wrote:
> I'm trying to understand strict-aliasing rule, that is an assumption
> that lets the compiler to better optimize the compilation process.
>
> If the strict-aliasing rule is disabled (maybe through
> -fno-strict-aliasing in gcc) the compiler can't assume the rule is valid
> and it can't optimize certain object accesses.
>
> In other words, if I don't want to break the rule, I can't access one
> object through a pointer to another object (even with casting):
>
> struct s1 *s1p;
> struct s2 *s2p = (struct s2 *)s1p;
>
> With -Wall (or -fstrict-aliasing) compiler gives a warning (and maybe
> the behaviour is undefined). With -fno-strict-aliasing, the warning
> disappears, the application always works but with an efficiency penalty.
>
>
> Now what about inheritance? I know it is possible to simulate the
> inheritance of OOP in C by defining the subclass as a structure with the
> first member as the superclass.
>
> typedef struct {
> int type;
> int color;
> } Shape;
>
> typedef struct {
> struct Shape super;
> int x1, x2, y1, y2;
> } Rect;
>
> So I can have a pointer to Shape or Rect by casting:
>
> Rect *r;
> Shape *s = (Shape *)r;
>
> Shape *s;
> if (s->type == RECT)
> {
> Rect *r;
> r = (Rect *)s;
> }
>
> However I think I'm breaking strict-aliasing rule, don't I?
I hope you get a proper answer.
However, I would like to say I stop worrying about that. Check
the behavior in your compiler.
Visual C++, for instance, uses the same memory layout for C and C++
to allow COM interfaces to be declared used in both languages.
Not only this, but C++ vtable is defined in a way that is acessible
in C.
C++ version
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
BEGIN_INTERFACE
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
END_INTERFACE
};
C version --
typedef struct IUnknownVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IUnknown * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IUnknown * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IUnknown * This);
END_INTERFACE
} IUnknownVtbl;
interface IUnknown
{
CONST_VTBL struct IUnknownVtbl *lpVtbl;
};
inheritance is done just starting the derived object with the
internals of the base.
[toc] | [prev] | [next] | [standalone]
| From | Steven Petruzzellis <frelwizzen@gmail.com> |
|---|---|
| Date | 2018-03-21 07:02 -0700 |
| Message-ID | <f1871ee8-80d7-4d02-a4c7-52ad7db6c122@googlegroups.com> |
| In reply to | #128138 |
On Wednesday, March 21, 2018 at 3:19:43 AM UTC-7, pozz wrote:
> I'm trying to understand strict-aliasing rule, that is an assumption
> that lets the compiler to better optimize the compilation process.
>
> If the strict-aliasing rule is disabled (maybe through
> -fno-strict-aliasing in gcc) the compiler can't assume the rule is valid
> and it can't optimize certain object accesses.
>
> In other words, if I don't want to break the rule, I can't access one
> object through a pointer to another object (even with casting):
>
> struct s1 *s1p;
> struct s2 *s2p = (struct s2 *)s1p;
>
> With -Wall (or -fstrict-aliasing) compiler gives a warning (and maybe
> the behaviour is undefined). With -fno-strict-aliasing, the warning
> disappears, the application always works but with an efficiency penalty.
>
>
> Now what about inheritance? I know it is possible to simulate the
> inheritance of OOP in C by defining the subclass as a structure with the
> first member as the superclass.
>
> typedef struct {
> int type;
> int color;
> } Shape;
>
> typedef struct {
> struct Shape super;
> int x1, x2, y1, y2;
> } Rect;
>
> So I can have a pointer to Shape or Rect by casting:
>
> Rect *r;
> Shape *s = (Shape *)r;
>
> Shape *s;
> if (s->type == RECT)
> {
> Rect *r;
> r = (Rect *)s;
> }
>
> However I think I'm breaking strict-aliasing rule, don't I?
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hi, Snit!
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - https://gpgtools.org
iQIcBAEBCgAGBQJYY/GZAAoJELnOYK54exUCoY8P/A2to3G0OJrV4rFZqrfos0G+
Hlz52idYDsiO9KbYI9E2AaEhX5Jado6kJgDD31LTOnYSHrIuTi/LeywcjOL/FCy7
bEojPW3xtu/XWHHSKU1Grce80Q2PHuR+878JDbCjXgrFplNEVk8+kiv2+5RlYegG
7xEgm+/J8zvxVlPfyoHOO65AygYy/ykShdza+MAW6OFWaXFNOxExjRx3mCmWcu3b
eyf0bxgzL4zAFCuPBAOXQ56vxO8AOuwk8F7mXLV2Vn2Q2OTcqrEYMjwQZ2q7wFSg
khU6VkEs7aFJ6keLSCoZlFmnoymptflJw3h0O6bb9GK67JBV6Moh5rev6aJfqGuZ
fo38FgD/eRVroAYSm3FSCcknNbUhdNLUO/JmCRtx62YQvZoyUqUL64YRGlJ+moAV
ZnU6NfI4WeeQ5nuagTS+kKjj1qGxsUkXEUTFRJpv4zQcHnTKTyUl+38t3+Jke7ua
NRtkWtIvgg9+JCsA1qHjDDP29hdR5v7KFFnRKBaVgV+/nrALANWybFJKYsqxpP95
LMd0pxvEy2ZlX9n3nkmMIn4iRX3dY795NgOzHGd1ZWtMS3BPu4QWFA/YS7Adb30Z
yHClb/JJWGtTPvgVtPzHyNbPhF6+kgJ/KQ6YrqiX71ZNLZNqCze7z3nw6xjcWr9V
soXbWlBBa6AX7lnolpK8
=hcV2
-----END PGP SIGNATURE-----
-
This Trick Gets Women Hot For You!!
https://groups.google.com/forum/#!topic/comp.os.linux.advocacy/smzXrBhsWf4
Jonas Eklundh Communication AB
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2018-03-21 10:31 -0400 |
| Message-ID | <p8tqca$eou$1@dont-email.me> |
| In reply to | #128138 |
On 03/21/2018 06:19 AM, pozz wrote:
> I'm trying to understand strict-aliasing rule, that is an assumption
> that lets the compiler to better optimize the compilation process.
>
> If the strict-aliasing rule is disabled (maybe through
> -fno-strict-aliasing in gcc) the compiler can't assume the rule is valid
> and it can't optimize certain object accesses.
>
> In other words, if I don't want to break the rule, I can't access one
> object through a pointer to another object (even with casting):
The actual rule's wording is more complicated than that, and you need to
look at that wording to resolve your question.
> struct s1 *s1p;
> struct s2 *s2p = (struct s2 *)s1p;
>
> With -Wall (or -fstrict-aliasing) compiler gives a warning (and maybe
> the behaviour is undefined). With -fno-strict-aliasing, the warning
> disappears, the application always works but with an efficiency penalty.
>
>
> Now what about inheritance? I know it is possible to simulate the
> inheritance of OOP in C by defining the subclass as a structure with the
> first member as the superclass.
>
> typedef struct {
> int type;
> int color;
> } Shape;
>
> typedef struct {
> struct Shape super;
> int x1, x2, y1, y2;
> } Rect;
>
> So I can have a pointer to Shape or Rect by casting:
>
> Rect *r;
> Shape *s = (Shape *)r;
"... A pointer to a structure object, suitably converted, points to its
initial member (or if that member is a bit-field, then to the unit in
which it resides), and vice versa. ..." (6.7.2.1p15).
r->super is the first member of Rect, and it seems to me that (Shape*)r
is obviously what it's referring to when it says "suitably converted" -
though I've seen people claim that what counts as "suitable" is unspecified.
However, assuming that 'r' is not null, it's safer to use
Shape *s = &r->super;
because a diagnostic is mandatory if 'super' doesn't exist (6.5.2.3p1)
or doesn't have a type compatible with Shape (6.5.16.1p1). You would
only need to use the conversion in code where r is null or Shape has an
incomplete type (and that would only be possible if Rect also has an
incomplete type).
> Shape *s;> if (s->type == RECT)
> {
> Rect *r;
> r = (Rect *)s;
> }
>
> However I think I'm breaking strict-aliasing rule, don't I?
C's anti-aliasing rule is 6.5p7:
> An object shall have its stored value accessed only by an lvalue
> expression that has one of the following types: 88)
> — a type compatible with the effective type of the object,
> — a qualified version of a type compatible with the effective type of
> the object,
> — a type that is the signed or unsigned type corresponding to the
> effective type of the object,
> — a type that is the signed or unsigned type corresponding to a
> qualified version of the effective type of the object,
> — an aggregate or union type that includes one of the aforementioned
> types among its members (including, recursively, a member of a
> subaggregate or contained union), or
> — a character type.
s points at r->super, so s->type is an lvalue of type 'int' referring to
r->super.type. "int" is not a qualified type, so the second and fourth
options don't apply. It isn't an aggregate or character type, so the
fifth and sixth options don't apply.
An lvalue of type "int" can therefore only be used to access
r->super.type if that object's effective type is "int", "unsigned int",
or one of an implementation-defined set of enumerated types that are
compatible with either of those types (6.7.2.2p4).
You haven't shown us how memory for the object that r points at was
allocated, nor how r->super.type obtained it's current value. This
matters because 6.5p6 says:
> The effective type of an object for an access to its stored value is the declared type of the
> object, if any. 87) If a value is stored into an object having no declared type through an
> lvalue having a type that is not a character type, then the type of the lvalue becomes the
> effective type of the object for that access and for subsequent accesses that do not modify
> the stored value. If a value is copied into an object having no declared type using
> memcpy or memmove, or is copied as an array of character type, then the effective type
> of the modified object for that access and for subsequent accesses that do not modify the
> value is the effective type of the object from which the value is copied, if it has one. For
> all other accesses to an object having no declared type, the effective type of the object is
> simply the type of the lvalue used for the access.
Footnote 87, referred to in that paragraph, points out that "Allocated
objects have no declared type". If r points at an object with static,
thread, or automatic storage duration, then that object's super.type
member has the declared type of 'int', which is therefore also it's
effective type.
If s->type refers to an object with allocated storage duration (if it's
in memory allocated by aligned_alloc, calloc, malloc, or realloc), then
that object starts out with no effective type. If any of the methods
mentioned in 6.5p6 has been used to give it an effective type other than
'int', only then there is a possibility of violating 6.5p7.
Typical use of code like what you've written would never create such a
situation.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2018-03-21 09:38 -0700 |
| Message-ID | <aa3324ff-2fda-41f5-8d60-1e315ad2e6ac@googlegroups.com> |
| In reply to | #128150 |
On Wednesday, March 21, 2018 at 9:31:53 AM UTC-5, James Kuyper wrote: > You haven't shown us how memory for the object that r points at was > allocated, nor how r->super.type obtained it's current value. This > matters because 6.5p6 says: > > The effective type of an object for an access to its stored value is the declared type of the > > object, if any. 87) If a value is stored into an object having no declared type through an > > lvalue having a type that is not a character type, then the type of the lvalue becomes the > > effective type of the object for that access and for subsequent accesses that do not modify > > the stored value. If a value is copied into an object having no declared type using > > memcpy or memmove, or is copied as an array of character type, then the effective type > > of the modified object for that access and for subsequent accesses that do not modify the > > value is the effective type of the object from which the value is copied, if it has one. For > > all other accesses to an object having no declared type, the effective type of the object is > > simply the type of the lvalue used for the access. > > Footnote 87, referred to in that paragraph, points out that "Allocated > objects have no declared type". If r points at an object with static, > thread, or automatic storage duration, then that object's super.type > member has the declared type of 'int', which is therefore also it's > effective type. The Effective Type rules are a codification of the absurd rationale given in Defect Report #28, which essentially says that because the act of writing a union member of type "int" and reading as "float" invokes Implementation- Defined Behavior, the act of writing an "int*" and reading a "float*" invokes Undefined Behavior; this in turn has been taken to suggest that since writing one union member and then writing another has fully defined behavior (leaving the union holding the last value written), likewise writing via "float*" and then via "int*". While the Effective Type rules are supposed to be a "clarification" of C89, they instead add needless complexity and confusion. The footnote about allocated objects makes things worse by suggesting that allocated storage is unique in its ability to change types.
[toc] | [prev] | [next] | [standalone]
| From | Nick Bowler <nbowler@draconx.ca> |
|---|---|
| Date | 2018-03-21 14:46 +0000 |
| Message-ID | <p8tr8f$e90$1@dont-email.me> |
| In reply to | #128138 |
On Wed, 21 Mar 2018 11:19:34 +0100, pozz wrote:
[...]
> Now what about inheritance? I know it is possible to simulate the
> inheritance of OOP in C by defining the subclass as a structure with the
> first member as the superclass.
>
> typedef struct {
> int type;
> int color;
> } Shape;
>
> typedef struct {
> struct Shape super;
> int x1, x2, y1, y2;
> } Rect;
Typically this sort of structure works well.
> So I can have a pointer to Shape or Rect by casting:
>
> Rect *r;
> Shape *s = (Shape *)r;
Assuming that this code occurs inside a function, then r has
indeterminate value and the behaviour of the following initializer
is undefined for that reason alone.
> However I think I'm breaking strict-aliasing rule, don't I?
In order to meaningfully answer this question, your example would
have to contain actual objects that are aliased in various ways.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2018-03-21 08:18 -0700 |
| Message-ID | <da855905-bcfc-4d2b-b3f7-5d247f58fd3e@googlegroups.com> |
| In reply to | #128138 |
On Wednesday, March 21, 2018 at 5:19:43 AM UTC-5, pozz wrote:
> I'm trying to understand strict-aliasing rule, that is an assumption
> that lets the compiler to better optimize the compilation process.
A literal reading of the rules are written would require that structs or
unions be accessed only using character types--it makes no exceptions even
for the member-access operator. Clearly it would be unreasonable for a
compiler to regard as unreachable any code which uses the "." or "->"
operators on members of non-character type, and to my knowledge no compiler
actually goes that far. Unfortunately, the authors of the Standard failed
to establish any principle for when an lvalue which is derived from an
lvalue of another type may be used to access the same storage as the lvalue
from which it is derived.
Although footnotes are non-normative, I think the most logical remedy would
be to interpret the footnote saying the rule is intended to describe what
assumptions a compiler can make about aliasing, and recognizing that aliasing
requires that between the time a particular reference is created and the last
time it is used to access a region of storage, some reference that is not
visibly associated with it is used to access that same storage in conflicting
fashion.
If a compiler recognizes derived lvalues in cases *that won't actually involve
aliasing* if code is executed as written, then most common patterns where one
would exploit the Common Initial Sequence guarantee would be safe.
Unfortunately, given something like:
MemberType1 *p1= &unionArray[i]->member1;
useMember1(p1);
MemberType1 *p2= &unionArray[j]->member2;
useMember2(p2);
MemberType1 *p3= &unionArray[i]->member1;
useMember1(p3);
Both gcc and clang will decide that they can treat the use of p3 as use
of p1, *even though that would create aliasing when none existed in the
original code*, without having to recognize the aliasing which was created
in the compiler.
Given that any code that does *anything* with struct and union members of
non-character type invokes UB, the behavior of gcc and clang is not non-
conforming. On the other hand, I think that compiler writers that would
interpret the aliasing rule as inviting compilers to ignore the possibility
of unionArray[i] and unionArray[j] identifying the same object should be
viewed as obtuse.
[toc] | [prev] | [next] | [standalone]
| From | Steven Petruzzellis <frelwizzen@gmail.com> |
|---|---|
| Date | 2018-03-21 23:23 -0700 |
| Message-ID | <afa00c11-0f57-45ed-8560-d89750f491cf@googlegroups.com> |
| In reply to | #128152 |
On Wednesday, March 21, 2018 at 8:18:37 AM UTC-7, supe...@casperkitty.com wrote: > On Wednesday, March 21, 2018 at 5:19:43 AM UTC-5, pozz wrote: > > I'm trying to understand strict-aliasing rule, that is an assumption > > that lets the compiler to better optimize the compilation process. > > A literal reading of the rules are written would require that structs or > unions be accessed only using character types--it makes no exceptions even > for the member-access operator. Clearly it would be unreasonable for a > compiler to regard as unreachable any code which uses the "." or "->" > operators on members of non-character type, and to my knowledge no compiler > actually goes that far. Unfortunately, the authors of the Standard failed > to establish any principle for when an lvalue which is derived from an > lvalue of another type may be used to access the same storage as the lvalue > from which it is derived. > > Although footnotes are non-normative, I think the most logical remedy would > be to interpret the footnote saying the rule is intended to describe what > assumptions a compiler can make about aliasing, and recognizing that aliasing > requires that between the time a particular reference is created and the last > time it is used to access a region of storage, some reference that is not > visibly associated with it is used to access that same storage in conflicting > fashion. > > If a compiler recognizes derived lvalues in cases *that won't actually involve > aliasing* if code is executed as written, then most common patterns where one > would exploit the Common Initial Sequence guarantee would be safe. > > Unfortunately, given something like: > > MemberType1 *p1= &unionArray[i]->member1; > useMember1(p1); > MemberType1 *p2= &unionArray[j]->member2; > useMember2(p2); > MemberType1 *p3= &unionArray[i]->member1; > useMember1(p3); > > Both gcc and clang will decide that they can treat the use of p3 as use > of p1, *even though that would create aliasing when none existed in the > original code*, without having to recognize the aliasing which was created > in the compiler. > > Given that any code that does *anything* with struct and union members of > non-character type invokes UB, the behavior of gcc and clang is not non- > conforming. On the other hand, I think that compiler writers that would > interpret the aliasing rule as inviting compilers to ignore the possibility > of unionArray[i] and unionArray[j] identifying the same object should be > viewed as obtuse. It was Malcolm McLean who flooded Vennie Bowden (https://www.bloomtreeprescott.com/staff/Vennie.Bowden)'s site hundreds of thousands of times and denied it. I would help Malcolm McLean directly but he is a blockhead who twists what you say to effect his appetite to call everyone a con artist. It's Malcolm McLean's problem and he has to want to deal with it. Obviously he would rather attack than face reality. I guess this is what comes about when seriously inferior pride takes over Malcolm McLean's entire life. I bet Malcolm McLean thinks your life was rough. You guys can only think from the viewpoint of a psychopath. Already moved on from that. Keep up! A persistent, fervid, posting itch, regardless of content - like gunky Mac-using prostitutes, and vigorously-greased ram, stuck in a mud hole for his own private fetishes. -- I Left My Husband & Daughter At Home And THIS happened https://www.youtube.com/watch?v=0ZNxaaKD7-c Jonas Eklundh
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2018-03-21 15:53 +0000 |
| Message-ID | <87h8p9tofh.fsf@bsb.me.uk> |
| In reply to | #128138 |
pozz <pozzugno@gmail.com> writes:
> I'm trying to understand strict-aliasing rule, that is an assumption
> that lets the compiler to better optimize the compilation process.
<snip>
> Now what about inheritance? I know it is possible to simulate the
> inheritance of OOP in C by defining the subclass as a structure with
> the first member as the superclass.
>
> typedef struct {
> int type;
> int color;
> } Shape;
>
> typedef struct {
> struct Shape super;
Shape super;
> int x1, x2, y1, y2;
> } Rect;
>
> So I can have a pointer to Shape or Rect by casting:
>
> Rect *r;
> Shape *s = (Shape *)r;
Shape *s = &r.super;
> Shape *s;
> if (s->type == RECT)
> {
> Rect *r;
> r = (Rect *)s;
I'd write Rect *r = (void *)s;
> }
>
> However I think I'm breaking strict-aliasing rule, don't I?
C has no "strict-aliasing rule". It has what are called effective type
rules and these say that you can't access an object of one type though
an lvalue expression of another type. That's a gross simplification of
course, but none of the details are in play here. Provided s->type is
never equal RECT when s is not, in fact, pointing at the Shape inside a
Rect, then you are not breaking C's rules when you write r->whatever.
There's been some suggestion that gcc's -fstrict-aliasing flag causes
gcc to make assumptions that are not warranted by C's effective type
rules, but I am not 100% if that is true (and it's likely to be version
dependent as well).
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2018-03-21 09:30 -0700 |
| Message-ID | <f8e43b88-b58c-4962-a582-282992b5de58@googlegroups.com> |
| In reply to | #128153 |
On Wednesday, March 21, 2018 at 10:54:06 AM UTC-5, Ben Bacarisse wrote:
> C has no "strict-aliasing rule". It has what are called effective type
> rules and these say that you can't access an object of one type though
> an lvalue expression of another type. That's a gross simplification of
> course, but none of the details are in play here. Provided s->type is
> never equal RECT when s is not, in fact, pointing at the Shape inside a
> Rect, then you are not breaking C's rules when you write r->whatever.
A literal reading of the rules would indicate that given:
struct foo {int x; } *p;
the lvalue "p->x" has type "int". As such, it may be used to access any
object whose type is simply "int", but may not be used to access any object
of type "struct foo".
The rules would make a lot of sense if "p->x" were regarded for purposes of
6.5p7 as an lvalue of type "struct foo", but I see nothing in the Standard
that would actually say such a thing. What the Standard actually says is,
of course, absurd, but its failure to say anything meaningful means that
code will behave predictably in cases compiler writers feel like supporting
and unpredictably in cases compiler writers don't feel like supporting.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2018-03-21 10:20 -0700 |
| Message-ID | <lnwoy5pcqa.fsf@kst-u.example.com> |
| In reply to | #128155 |
supercat@casperkitty.com writes:
> On Wednesday, March 21, 2018 at 10:54:06 AM UTC-5, Ben Bacarisse wrote:
>> C has no "strict-aliasing rule". It has what are called effective type
>> rules and these say that you can't access an object of one type though
>> an lvalue expression of another type. That's a gross simplification of
>> course, but none of the details are in play here. Provided s->type is
>> never equal RECT when s is not, in fact, pointing at the Shape inside a
>> Rect, then you are not breaking C's rules when you write r->whatever.
>
> A literal reading of the rules would indicate that given:
>
> struct foo {int x; } *p;
>
> the lvalue "p->x" has type "int". As such, it may be used to access any
> object whose type is simply "int", but may not be used to access any object
> of type "struct foo".
Of course p->x is of type int.
> The rules would make a lot of sense if "p->x" were regarded for purposes of
> 6.5p7 as an lvalue of type "struct foo"
No, it would make no sense at all to treat p->x as an lvalue of type
struct foo. Would you want this to be legal?
struct foo {int x; } *p;
struct foo obj;
// assume reasonable initializations
p->x = obj;
If p->x is regarded as an lvalue of type struct foo, why would that last
assignment not be legal?
*p is of type struct foo because p is defined as an object of type
struct foo*. p->x is of type int because x is defined as a member of
type int.
[...]
--
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@casperkitty.com |
|---|---|
| Date | 2018-03-21 10:54 -0700 |
| Message-ID | <dc6a4f94-5848-4361-806f-1cb901c24214@googlegroups.com> |
| In reply to | #128159 |
On Wednesday, March 21, 2018 at 12:20:25 PM UTC-5, Keith Thompson wrote:
> supercat@casperkitty.com writes:
> > A literal reading of the rules would indicate that given:
> >
> > struct foo {int x; } *p;
> >
> > the lvalue "p->x" has type "int". As such, it may be used to access any
> > object whose type is simply "int", but may not be used to access any object
> > of type "struct foo".
>
> Of course p->x is of type int.
>
> > The rules would make a lot of sense if "p->x" were regarded for purposes of
> > 6.5p7 as an lvalue of type "struct foo"
>
> No, it would make no sense at all to treat p->x as an lvalue of type
> struct foo. Would you want this to be legal?
>
> struct foo {int x; } *p;
> struct foo obj;
> // assume reasonable initializations
> p->x = obj;
For purposes *other than 6.5p7* the normal meanings would apply.
> If p->x is regarded as an lvalue of type struct foo, why would that last
> assignment not be legal?
Because portions of the Standard other than 6.5p7 would forbid it.
I'm only suggesting the alternate meaning *for purposes of 6.5p7*; an
alternative way of saying the same thing would be to reword 6.7p7 to refer
to something other than the "type" of the lvalue.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2018-03-21 11:48 -0700 |
| Message-ID | <lno9jhp8mj.fsf@kst-u.example.com> |
| In reply to | #128164 |
supercat@casperkitty.com writes:
> On Wednesday, March 21, 2018 at 12:20:25 PM UTC-5, Keith Thompson wrote:
>> supercat@casperkitty.com writes:
>> > A literal reading of the rules would indicate that given:
>> >
>> > struct foo {int x; } *p;
>> >
>> > the lvalue "p->x" has type "int". As such, it may be used to access any
>> > object whose type is simply "int", but may not be used to access any object
>> > of type "struct foo".
>>
>> Of course p->x is of type int.
>>
>> > The rules would make a lot of sense if "p->x" were regarded for purposes of
>> > 6.5p7 as an lvalue of type "struct foo"
>>
>> No, it would make no sense at all to treat p->x as an lvalue of type
>> struct foo. Would you want this to be legal?
>>
>> struct foo {int x; } *p;
>> struct foo obj;
>> // assume reasonable initializations
>> p->x = obj;
>
> For purposes *other than 6.5p7* the normal meanings would apply.
>
>> If p->x is regarded as an lvalue of type struct foo, why would that last
>> assignment not be legal?
>
> Because portions of the Standard other than 6.5p7 would forbid it.
>
> I'm only suggesting the alternate meaning *for purposes of 6.5p7*; an
> alternative way of saying the same thing would be to reword 6.7p7 to refer
> to something other than the "type" of the lvalue.
It's conceivable that you could construct a consistent description given
this change. But I'm having difficulty expressing just how absurd your
idea is. p->x is not of type struct foo, it's of type int. Pretending
for any purpose that it's of type struct foo is just silly.
--
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@casperkitty.com |
|---|---|
| Date | 2018-03-21 14:28 -0700 |
| Message-ID | <d5f8870b-4da4-4b37-b16f-c0d40ad178db@googlegroups.com> |
| In reply to | #128165 |
On Wednesday, March 21, 2018 at 1:49:06 PM UTC-5, Keith Thompson wrote:
> supercat@casperkitty.com writes:
> > I'm only suggesting the alternate meaning *for purposes of 6.5p7*; an
> > alternative way of saying the same thing would be to reword 6.7p7 to refer
> > to something other than the "type" of the lvalue.
>
> It's conceivable that you could construct a consistent description given
> this change. But I'm having difficulty expressing just how absurd your
> idea is. p->x is not of type struct foo, it's of type int. Pretending
> for any purpose that it's of type struct foo is just silly.
The Standard as written is nonsensical, though I just realized another
problem with it which--if fixed--would also fix the Standard. Even
something like:
char i;
i=1;
invokes UB because 6.5p7 says "An object shall have its stored value
accessed only by an lvalue expression that has one of the following
types:...", and the expression "i=1" isn't an lvalue.
If the Standard were changed to add a single word: "An object shall have
its stored value accessed only by *USING* an lvalue expression that has
one of the following types:...", then the Standard could specify cases
where use of a derived lvalue would also represent "use" of the original.
If one recognizes that use of a derived lvalue D to access a region of
storage must be recognized as use of the original at least until one
of the following occurs:
1. An lvalue not derived from D is used to access the same storage
in conflicting fashion (writes conflict with reads and writes, but
reads do not conflict with reads).
2. An lvalue not derived from D is used to derive another lvalue which
will be used to access the same storage in conflicting fashion.
3. Code reaches the start of a function or bona fide loop where one of
the preceding occurs.
that would seem a reasonable definition of "use", and would accommodate most
programming needs, while allowing nearly all genuinely-useful optimizations.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2018-03-21 21:39 +0000 |
| Message-ID | <slrnpb5k8g.eu5.grahn+nntp@frailea.sa.invalid> |
| In reply to | #128138 |
On Wed, 2018-03-21, pozz wrote: > I'm trying to understand strict-aliasing rule, that is an assumption > that lets the compiler to better optimize the compilation process. > > If the strict-aliasing rule is disabled (maybe through > -fno-strict-aliasing in gcc) the compiler can't assume the rule is valid > and it can't optimize certain object accesses. > > In other words, if I don't want to break the rule, I can't access one > object through a pointer to another object (even with casting): > > struct s1 *s1p; > struct s2 *s2p = (struct s2 *)s1p; ... This predictably restarted the usual endless discussion about supercat's quest for 1970s C. I'll just offer my personal rule: Don't do bizarre casts between pointer types. IMO doing them is almost always a mistake, even if you don't consider aliasing. Exception: when some API (like the BSD Sockets API) forces you to; then someone else carries the burden of correctness. ... > Now what about inheritance? I know it is possible to simulate the > inheritance of OOP in C by defining the subclass as a structure with the > first member as the superclass. I seriously doubt there is a benefit in trying to do that. Creating "classes" in C is IMO useful, but once you're trying to simulate inheritance (with or without run-time polymorphism) you're pushing it too far. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o .
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web