Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Yet another binary search tree library

Reply
Thread Tools

Yet another binary search tree library

 
 
Ersek, Laszlo
Guest
Posts: n/a
 
      07-15-2010
On Wed, 14 Jul 2010, Tim Rentsch wrote:

> Franck Bui-Huu <> writes:
>
>> "Ersek, Laszlo" <> writes:
>>
>>>>
>>>> struct object *the_obj;
>>>> the_obj = avltree_container_of(the_node, struct object , node);
>>>> assert(the_obj->key == 4);
>>>
>>> Therein lies my problem:
>>>
>>> #define avltree_container_of(node, type, member) ({ \
>>> const struct avltree_node *__mptr = (node); \
>>> (type *)( (char *)__mptr - offsetof(type,member) );})
>>>


[snip]

>>> Second (my main concern), I suspect that this breaks strict aliasing
>>> rules. That is, after the avltree_container_of() function-like macro
>>> is expanded and the (statement-)expression is evaluated, you end up
>>> with two pointers, namely "the_node" and "the_obj". They point to
>>> storage that overlaps, and none of them was computed from the other by
>>> following pointers and taking addresses of members.
>>>
>>> That is, you have two pointers to different types, the pointed-to
>>> areas overlap, and you obtained one of the pointers by type-punning
>>> (when you cast the pointer-to-char to pointer-to-type).


[snip]

>> Therefore,
>>
>> (char *)node - offsetof(...)
>>
>> results to the address of the beginning of the structure (whose type is
>> 'struct my_struct) containing the member 'my_node' pointed by 'node'.
>>
>> So by definition we can assume that this address is correctly aligned
>> for accessing an object of type 'struct my_struct'. Therefore we can
>> safely convert back this address to (struct my_struct *).
>>
>> And since we know that the effective type of the underlying object is
>> 'struct my_struct', it's safe to deference the converted pointer.

>
> Right.
>
>> So to sum up, I think:
>>
>> struct my_struct obj;
>> char *p = (char *)&obj;
>> p += offsetof(struct my_struct, my_node);
>> p -= offsetof(struct my_struct, my_node);
>> ((struct my_struct *)p)->a;
>>
>> is a defined case of type punning.

>
> Actually there isn't any type punning going on here, since the types
> used to reference objects are the same in each case that the respective
> object actually holds. (And ignoring that member 'a' hasn't been
> initialized, which is orthogonal to the question of type punning.)
> Type punning refers to the case when a region of memory has been stored
> (or perhaps declared) using one type, then accessed using another.
> That hasn't happened here. The pointer conversions are legal and
> portable, but the converted pointers are accessing objects whose types
> match those of the access in each case -- ergo, no type punning.


I probably misused the term "type punning" (see above what I meant --
nothing more than manipulating a pointer-to-char and then casting it to a
pointer-to-struct).

My real problem was, again, that the compiler sees two pointers to
different types, and the areas occupied by the pointed-to objects overlap.
I was worried whether this breaks "strict aliasing rules".

Of course, it doesn't; the outer structure declaration ("struct
object_type") is visible, so if the compiler sees a (struct object_type *)
and a (struct node_type *), it cannot assume the latter doesn't point into
the target of the former -- unless "restrict" is in effect.


I attribute my mistake to two specific "shocks" I suffered earlier: (1)
the struct hack is UB in C89, and (2) if "arr" is a two-by-two "matrix",
you can't write "arr[0][3]". These presumably drove me to the overcautious
extreme.

I have to admit, I still have difficulty determining what constitutes a
promise to the compiler. Consider:

a) It was derived by multiple illustrious contributors here and in c.l.c.m
that multi-dimensional arrays can't have holes at all (or so I remember).
It had to be derived because the Standard doesn't explicitly say so (I
think). Why oh why can't you write arr[0][3] then, when the memory *must*
be there and the access is correctly aligned? Well, because you made a
promise to the compiler wrt. to the range of the last subscript, and the
addressing instruction it generates may be invalid.

Okay, then write "*(&arr[0][0] + 3)". Still undefined, because...

Or, instead of over-indexing a struck hack array in C89, just write

*(el_type *)((char unsigned *)hack_arr + n * sizeof(el_type))

Still undefined, because...

b) Contrast: hacking on a char pointer, casting it and dereferencing it is
okay, because "we know it is correctly aligned, and the pointed-to storage
was correctly allocated and written to earlier".

I simply can't put my finger on the distinctive feature between these two.

--o--

Thanks for your reply, Tim.
lacos
 
Reply With Quote
 
 
 
 
Francis Moreau
Guest
Posts: n/a
 
      07-17-2010
On Jul 15, 7:34*pm, "Ersek, Laszlo" <la...@caesar.elte.hu> wrote:
> On Wed, 14 Jul 2010, Tim Rentsch wrote:
> > Franck Bui-Huu <franck....@gmail.com> writes:

>
> >> "Ersek, Laszlo" <la...@caesar.elte.hu> writes:

>
> >>>> * * * *struct object *the_obj;
> >>>> * * * *the_obj = avltree_container_of(the_node, struct object , node);
> >>>> * * * *assert(the_obj->key == 4);

>
> >>> Therein lies my problem:

>
> >>> #define avltree_container_of(node, type, member) ({ * * * \
> >>> * * const struct avltree_node *__mptr = (node); * * * * * \
> >>> * * (type *)( (char *)__mptr - offsetof(type,member) );})

>
> [snip]
>
> >>> Second (my main concern), I suspect that this breaks strict aliasing
> >>> rules. That is, after the avltree_container_of() function-like macro
> >>> is expanded and the (statement-)expression is evaluated, you end up
> >>> with two pointers, namely "the_node" and "the_obj". They point to
> >>> storage that overlaps, and none of them was computed from the other by
> >>> following pointers and taking addresses of members.

>
> >>> That is, you have two pointers to different types, the pointed-to
> >>> areas overlap, and you obtained one of the pointers by type-punning
> >>> (when you cast the pointer-to-char to pointer-to-type).

>
> [snip]
>
>
>
>
>
> >> Therefore,

>
> >> * * * * (char *)node - offsetof(...)

>
> >> results to the address of the beginning of the structure (whose type is
> >> 'struct my_struct) containing the member 'my_node' pointed by 'node'.

>
> >> So by definition we can assume that this address is correctly aligned
> >> for accessing an object of type 'struct my_struct'. Therefore we can
> >> safely convert back this address to (struct my_struct *).

>
> >> And since we know that the effective type of the underlying object is
> >> 'struct my_struct', it's safe to deference the converted pointer.

>
> > Right.

>
> >> So to sum up, I think:

>
> >> * * * * struct my_struct obj;
> >> * * * * char *p = (char *)&obj;
> >> * * * * p += offsetof(struct my_struct, my_node);
> >> * * * * p -= offsetof(struct my_struct, my_node);
> >> * * * * ((struct my_struct *)p)->a;

>
> >> is a defined case of type punning.

>
> > Actually there isn't any type punning going on here, since the types
> > used to reference objects are the same in each case that the respective
> > object actually holds. *(And ignoring that member 'a' hasn't been
> > initialized, which is orthogonal to the question of type punning.)
> > Type punning refers to the case when a region of memory has been stored
> > (or perhaps declared) using one type, then accessed using another.
> > That hasn't happened here. *The pointer conversions are legal and
> > portable, but the converted pointers are accessing objects whose types
> > match those of the access in each case -- ergo, no type punning.

>
> I probably misused the term "type punning" (see above what I meant --
> nothing more than manipulating a pointer-to-char and then casting it to a
> pointer-to-struct).
>
> My real problem was, again, that the compiler sees two pointers to
> different types, and the areas occupied by the pointed-to objects overlap..
> I was worried whether this breaks "strict aliasing rules".
>
> Of course, it doesn't; the outer structure declaration ("struct
> object_type") is visible, so if the compiler sees a (struct object_type *)
> and a (struct node_type *), it cannot assume the latter doesn't point into
> the target of the former -- unless "restrict" is in effect.
>


Really ?

I thought that "strict aliasing rules" force the compiler to assume
that 2 different types never overlap.

BTW, are these rules specific to GCC ?

Thanks
 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      07-17-2010
"Ersek, Laszlo" <> writes:

> On Wed, 14 Jul 2010, Tim Rentsch wrote:
>
>> Franck Bui-Huu <> writes:
>>
>>> "Ersek, Laszlo" <> writes:
>>>
>>>>>
>>>>> struct object *the_obj;
>>>>> the_obj = avltree_container_of(the_node, struct object , node);
>>>>> assert(the_obj->key == 4);
>>>>
>>>> Therein lies my problem:
>>>>
>>>> #define avltree_container_of(node, type, member) ({ \
>>>> const struct avltree_node *__mptr = (node); \
>>>> (type *)( (char *)__mptr - offsetof(type,member) );})
>>>>

>
> [snip]
>
>>>> Second (my main concern), I suspect that this breaks strict
>>>> aliasing rules. That is, after the avltree_container_of()
>>>> function-like macro is expanded and the (statement-)expression is
>>>> evaluated, you end up with two pointers, namely "the_node" and
>>>> "the_obj". They point to storage that overlaps, and none of them
>>>> was computed from the other by following pointers and taking
>>>> addresses of members.
>>>>
>>>> That is, you have two pointers to different types, the pointed-to
>>>> areas overlap, and you obtained one of the pointers by
>>>> type-punning (when you cast the pointer-to-char to
>>>> pointer-to-type).

>
> [snip]
>
>>> Therefore,
>>>
>>> (char *)node - offsetof(...)
>>>
>>> results to the address of the beginning of the structure (whose
>>> type is 'struct my_struct) containing the member 'my_node' pointed
>>> by 'node'.
>>>
>>> So by definition we can assume that this address is correctly
>>> aligned for accessing an object of type 'struct
>>> my_struct'. Therefore we can safely convert back this address to
>>> (struct my_struct *).
>>>
>>> And since we know that the effective type of the underlying object
>>> is 'struct my_struct', it's safe to deference the converted
>>> pointer.

>>
>> Right.
>>
>>> So to sum up, I think:
>>>
>>> struct my_struct obj;
>>> char *p = (char *)&obj;
>>> p += offsetof(struct my_struct, my_node);
>>> p -= offsetof(struct my_struct, my_node);
>>> ((struct my_struct *)p)->a;
>>>
>>> is a defined case of type punning.

>>
>> Actually there isn't any type punning going on here, since the types
>> used to reference objects are the same in each case that the
>> respective object actually holds. (And ignoring that member 'a'
>> hasn't been initialized, which is orthogonal to the question of type
>> punning.) Type punning refers to the case when a region of memory
>> has been stored (or perhaps declared) using one type, then accessed
>> using another. That hasn't happened here. The pointer conversions
>> are legal and portable, but the converted pointers are accessing
>> objects whose types match those of the access in each case -- ergo,
>> no type punning.

>
> I probably misused the term "type punning" (see above what I meant --
> nothing more than manipulating a pointer-to-char and then casting it
> to a pointer-to-struct).


Yes, I realized the confusion and hoped my comments might
clear that up.

> My real problem was, again, that the compiler sees two pointers to
> different types, and the areas occupied by the pointed-to objects
> overlap. I was worried whether this breaks "strict aliasing rules".
>
> Of course, it doesn't; the outer structure declaration ("struct
> object_type") is visible, so if the compiler sees a (struct
> object_type *) and a (struct node_type *), it cannot assume the latter
> doesn't point into the target of the former -- unless "restrict" is in
> effect.
>
>
> I attribute my mistake to two specific "shocks" I suffered earlier:
> (1) the struct hack is UB in C89, and (2) if "arr" is a two-by-two
> "matrix", you can't write "arr[0][3]". These presumably drove me to
> the overcautious extreme.
>
> I have to admit, I still have difficulty determining what constitutes
> a promise to the compiler. Consider:
>
> a) It was derived by multiple illustrious contributors here and in
> c.l.c.m that multi-dimensional arrays can't have holes at all (or so I
> remember). It had to be derived because the Standard doesn't
> explicitly say so (I think). Why oh why can't you write arr[0][3]
> then, when the memory *must* be there and the access is correctly
> aligned? Well, because you made a promise to the compiler wrt. to the
> range of the last subscript, and the addressing instruction it
> generates may be invalid.
>
> Okay, then write "*(&arr[0][0] + 3)". Still undefined, because...
>
> Or, instead of over-indexing a struck hack array in C89, just write
>
> *(el_type *)((char unsigned *)hack_arr + n * sizeof(el_type))
>
> Still undefined, because...
>
> b) Contrast: hacking on a char pointer, casting it and dereferencing
> it is okay, because "we know it is correctly aligned, and the
> pointed-to storage was correctly allocated and written to earlier".
>
> I simply can't put my finger on the distinctive feature between these two.


I find it useful to read the Standard in two distinct modes.
One, what I might call the "comp.std.c mode", is a more literal
and less assuming reading (or interpretation, some might say).
The other, what I might call the "comp.lang.c mode", is less
literal and allows more reading between the lines, in an effort
to discover what the committee expects for how the words will
be read. Mostly these two modes produce the same conclusions,
but there are some obvious counterexamples, and I think pointer
manipulation and conversion qualifies as a candidate here.

Reading in the comp.lang.c mode, indexing an array past its
(last dimension) index limit is wrong, because the compiler
"knows" (more accurately, "is allowed to know") what that
upper bound is. So that explains the 'arr[0][3]' example.
Furthermore, because of how indexing works in C (because of
how arrays convert to pointer-to-first-element) the expression
'*(&arr[0][0]+3)' isn't any different than '*(&arr[0][3])',
which obviously should be the same as 'arr[0][3]'.

The third example (with 'hack_arr') is a little tricker, because
casting a pointer to any kind of character pointer carries a certain
amount of "magic" in the C language, so this is closer to being
allowed. There's a different problem though, which is storing into
any structure member is allowed to mess up any padding bytes, so the
(presumably last) member 'hack_arr' might be messed up by that in
its upper bytes. I think a reasonable argument could be made that
if the size of 'hack_arr' plus its offset in the structure equals
the size of the whole structure (ie, so there are no trailing
padding bytes), then accessing 'hack_arr' in the way you describe
can be expected to work (again reading in the comp.lang.c mode, and
even so I admit it's a gray area).

The difference with converting to a structure pointer is (a) we
know (again, in comp.lang.c mode) that we have to be able to do
pointer arithmetic on a character pointer to get from a
pointer-to-member to pointer-to-structure, because otherwise
what's the point of 'offsetof()', and (b) when we convert a
pointer to a pointer-to-structure, whatever the compiler used to
"know" about the size of the pointed-to object, now it "knows"
something different, ie, the size of the structure, because that
information is explicit in the definition of the structure type,
and C is supposed to "trust the programmer". The explicit
supplying of new size information is the key difference between
the two cases. At least, I think that's a reasonable conclusion,
reading in the comp.lang.c mode.

Some people who read in more of a comp.std.c mode might argue that
going from pointer-to-(nonfirst)member to pointer-to-structure is
always undefined behavior, and I think it might be possible to make
an argument that the Standard supports such a reading. However,
as far as comp.lang.c goes, any sort of suggestion in that direction
is merely evidence that the Standard needs to be revised and/or
clarified, because surely the committee expects that this kind
of character pointer arithmetic works and yields the expected
(and well-defined) results.
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      07-17-2010
Francis Moreau <> writes:

> On Jul 15, 7:34 pm, "Ersek, Laszlo" <la...@caesar.elte.hu> wrote:
>>[snip]
>> My real problem was, again, that the compiler sees two pointers to
>> different types, and the areas occupied by the pointed-to objects overlap.
>> I was worried whether this breaks "strict aliasing rules".
>>
>> Of course, it doesn't; the outer structure declaration ("struct
>> object_type") is visible, so if the compiler sees a (struct object_type *)
>> and a (struct node_type *), it cannot assume the latter doesn't point into
>> the target of the former -- unless "restrict" is in effect.
>>

>
> Really ?
>
> I thought that "strict aliasing rules" force the compiler to assume
> that 2 different types never overlap.


The 'effective type' rules allow members of structures (ie, the
types of such members) to overlap the structure (type) to which
they belong, for obvious reasons.

> BTW, are these rules specific to GCC ?


No, effective type rules are defined in the ISO C Standard.
What I believe is specific to GCC is that GCC uses the
term "strict aliasing rules" rather than 'effective type'
which is the term used in the Standard. (Also GCC may
provide options to allow more restrictive or less restrictive
aliasing rules, but that's outside the scope of what's
being discussed above.)
 
Reply With Quote
 
Francis Moreau
Guest
Posts: n/a
 
      07-18-2010
Tim Rentsch <> writes:

> Francis Moreau <> writes:


[...]

>>
>> I thought that "strict aliasing rules" force the compiler to assume
>> that 2 different types never overlap.

>
> The 'effective type' rules allow members of structures (ie, the
> types of such members) to overlap the structure (type) to which
> they belong, for obvious reasons.


I assume you're talking about the rules given by 6.5p7.

I would call these rules, or specially this one,

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

the 'relax aliasing rule'. This rule is actually very annoying since
it
forces the compiler to generate not optimized code for no good reasons
in 90% of all cases.

Now let's see what are the "strict aliasing rules" from the gcc
manpage:

Allow the compiler to assume the strictest aliasing rules applicable
to the language being compiled. For C (and C^++), this activates
optimizations based on the type of expressions. In particular, an
object of one type is assumed never to reside at the same address as
an object of a different type, unless the types are almost the same.

>> BTW, are these rules specific to GCC ?

>
> No, effective type rules are defined in the ISO C Standard.
> What I believe is specific to GCC is that GCC uses the
> term "strict aliasing rules" rather than 'effective type'
> which is the term used in the Standard.


Looking at the 2 different rules (relax vs strict), they don't have
the
same meaning at all.

So it doesn't seem to me that "strict aliasing rule" is just a name
used
by GCC to mean the same rules given by C standard.

--
Francis
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      07-18-2010
Francis Moreau <> writes:

> Tim Rentsch <> writes:
>
>> Francis Moreau <> writes:

>
> [...]
>
>>>
>>> I thought that "strict aliasing rules" force the compiler to assume
>>> that 2 different types never overlap.

>>
>> The 'effective type' rules allow members of structures (ie, the
>> types of such members) to overlap the structure (type) to which
>> they belong, for obvious reasons.

>
> I assume you're talking about the rules given by 6.5p7.
>
> I would call these rules, or specially this one,
>
> 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
>
> the 'relax aliasing rule'.


You're free to call it whatever you want, but I believe this
usage is at odds with what most others understand, including
the GCC folks.

> This rule is actually very annoying since it
> forces the compiler to generate not optimized code for no good reasons
> in 90% of all cases.


Oh? You think taking a pointer to a structure member shouldn't
be allowed to access the member without causing undefined
behavior? Wouldn't that break essentially every large C program
in existence?

> Now let's see what are the "strict aliasing rules" from the gcc
> manpage:
>
> Allow the compiler to assume the strictest aliasing rules applicable
> to the language being compiled. For C (and C^++), this activates
> optimizations based on the type of expressions. In particular, an
> object of one type is assumed never to reside at the same address as
> an object of a different type, unless the types are almost the same.


Please note the last line -- "unless the types are almost the same."
It seems highly likely that gcc would transgress the rules for
structure/member intermixing, even under the heading of "strict
aliasing". The description in the gcc man page makes it clear
that unions are affected, but it's not completely clear what
the C Standard itself expects in such situations. The testing
I have done doesn't show any difference between 'effective type'
and 'strict aliasing', except (possibly) for the one example
with unions shown in the gcc man page, and again it's debatable
what the C Standard actually requires in such cases.


>>> BTW, are these rules specific to GCC ?

>>
>> No, effective type rules are defined in the ISO C Standard.
>> What I believe is specific to GCC is that GCC uses the
>> term "strict aliasing rules" rather than 'effective type'
>> which is the term used in the Standard.

>
> Looking at the 2 different rules (relax vs strict), they don't have
> the
> same meaning at all.
>
> So it doesn't seem to me that "strict aliasing rule" is just a name
> used
> by GCC to mean the same rules given by C standard.


I believe you have misunderstood the intended meaning of the gcc
documentation. Clearly that documentation can (and IMO should)
be better written than it is, but surely such a large deviation
away from what the C Standard requires would have a more strongly
worded description, if such a change was indeed intended.
 
Reply With Quote
 
Ersek, Laszlo
Guest
Posts: n/a
 
      07-19-2010
On Sat, 17 Jul 2010, Tim Rentsch wrote:

> I find it useful to read the Standard in two distinct modes. One, what I
> might call the "comp.std.c mode", is a more literal and less assuming
> reading (or interpretation, some might say). The other, what I might
> call the "comp.lang.c mode", is less literal and allows more reading
> between the lines, in an effort to discover what the committee expects
> for how the words will be read. Mostly these two modes produce the same
> conclusions, but there are some obvious counterexamples [...]


It's great to see these "modes" "formalized"; being aware of them will
help me read the Standard.

Thanks!
lacos
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      07-19-2010
"Ersek, Laszlo" <> writes:

> On Sat, 17 Jul 2010, Tim Rentsch wrote:
>
>> I find it useful to read the Standard in two distinct modes. One,
>> what I might call the "comp.std.c mode", is a more literal and less
>> assuming reading (or interpretation, some might say). The other,
>> what I might call the "comp.lang.c mode", is less literal and allows
>> more reading between the lines, in an effort to discover what the
>> committee expects for how the words will be read. Mostly these two
>> modes produce the same conclusions, but there are some obvious
>> counterexamples [...]

>
> It's great to see these "modes" "formalized"; being aware of them will
> help me read the Standard.


It also can be helpful in newsgroup discussions, because different
people make different assumptions about what the "correct" mode
is. If their respective mode assumptions are very different, it's
hard for two (or more) arguing posters to communicate effectively,
especially if each believes that his mode is the only correct one.
 
Reply With Quote
 
Francis Moreau
Guest
Posts: n/a
 
      07-19-2010
Tim Rentsch <> writes:

> Francis Moreau <> writes:
>
>> Tim Rentsch <> writes:
>>
>>> Francis Moreau <> writes:

>>
>> [...]
>>
>>>>
>>>> I thought that "strict aliasing rules" force the compiler to assume
>>>> that 2 different types never overlap.
>>>
>>> The 'effective type' rules allow members of structures (ie, the
>>> types of such members) to overlap the structure (type) to which
>>> they belong, for obvious reasons.

>>
>> I assume you're talking about the rules given by 6.5p7.
>>
>> I would call these rules, or specially this one,
>>
>> 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
>>
>> the 'relax aliasing rule'.

>
> You're free to call it whatever you want, but I believe this
> usage is at odds with what most others understand, including
> the GCC folks.
>
>> This rule is actually very annoying since it
>> forces the compiler to generate not optimized code for no good reasons
>> in 90% of all cases.

>
> Oh? You think taking a pointer to a structure member shouldn't
> be allowed to access the member without causing undefined
> behavior? Wouldn't that break essentially every large C program
> in existence?


No, the item of 6.5p7 which I pointed out doesn't deal about:

struct object {
int a;
};

[...]

struct object an_object;
int *p = &an_object.a;

As you said, this is clearly defined, since we're accessing the
(member)
object "an_object.a" with a pointer whose type is compatible.

However doing this:

struct object *obj;
int a = 5;
obj = (struct object *)&a;

is defined by the C standard AFAIK (by what you call 'effective type
rules' I believe, but 'strict aliasing rules' defined by GCC breaks
this
rules.

At that point, I'm quite confused

--
Francis
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      07-19-2010
Francis Moreau <> writes:

> Tim Rentsch <> writes:
>
>> Francis Moreau <> writes:
>>
>>> Tim Rentsch <> writes:
>>>
>>>> Francis Moreau <> writes:
>>>
>>> [...]
>>>
>>>>>
>>>>> I thought that "strict aliasing rules" force the compiler to assume
>>>>> that 2 different types never overlap.
>>>>
>>>> The 'effective type' rules allow members of structures (ie, the
>>>> types of such members) to overlap the structure (type) to which
>>>> they belong, for obvious reasons.
>>>
>>> I assume you're talking about the rules given by 6.5p7.
>>>
>>> I would call these rules, or specially this one,
>>>
>>> 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
>>>
>>> the 'relax aliasing rule'.

>>
>> You're free to call it whatever you want, but I believe this
>> usage is at odds with what most others understand, including
>> the GCC folks.
>>
>>> This rule is actually very annoying since it
>>> forces the compiler to generate not optimized code for no good reasons
>>> in 90% of all cases.

>>
>> Oh? You think taking a pointer to a structure member shouldn't
>> be allowed to access the member without causing undefined
>> behavior? Wouldn't that break essentially every large C program
>> in existence?

>
> No, the item of 6.5p7 which I pointed out doesn't deal about:
>
> struct object {
> int a;
> };
>
> [...]
>
> struct object an_object;
> int *p = &an_object.a;
>
> As you said, this is clearly defined, since we're accessing the
> (member) object "an_object.a" with a pointer whose type is compatible.


Right, but this case isn't what I was asking about.

> However doing this:
>
> struct object *obj;
> int a = 5;
> obj = (struct object *)&a;
>
> is defined by the C standard AFAIK (by what you call 'effective type
> rules' I believe, but 'strict aliasing rules' defined by GCC breaks
> this rules. [snip]


For starters this is (usually) undefined behavior anyway, because
of pointer alignments and size mismatches if nothing else.

However, suppose we have this:

int *p;
struct { int a; int b; } *x, *y;
x = malloc( sizeof *x );
y = malloc( sizeof *y );
/* presume the mallocs succeed */

y->a = y->b = 0;
*x = *y;
p = &x->a;

*p = 5;
*x = *y;
/* under strict aliasing must '*p == 0' still be true? */

*x = *y;
*p = 7;
*y = *x;
/* under strict aliasing must 'y->a == 7' still be true? */

y->a = y->b = 0;
*x = *y;
*p = 9;
x = (void*) p;
*x = *y;
/* under strict aliasing must '*p == 0' still be true? */

Do you believe, even under gcc strict aliasing, that any of the
comment questions can have an answer other than "Yes"?. If so,
what leads you to that conclusion?

My best understanding is that all these questions have the answer
"Yes" (more exactly, that gcc is expected to produce code
compatible with "Yes", so if it doesn't the result would be
labelled a bug).
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Binary tree search vs Binary search Bogdan C Programming 22 10-21-2010 09:46 PM
Hi, I want to implement a General Tree Data structure (Not Binary Tree ) which have more than 2 sub nodes? sharan C Programming 2 10-31-2007 02:58 AM
Hi, I want to implement a General Tree Data structure (Not Binary Tree ) which have more than 2 sub nodes? sharan C Programming 1 10-30-2007 11:01 PM
Hi, I want to implement a General Tree Data structure (Not Binary Tree ) which have more than 2 sub nodes? sharan C Programming 4 10-30-2007 08:21 PM
B tree, B+ tree and B* tree Stub C Programming 3 11-12-2003 01:51 PM



Advertisments