Re: Pointer to "base" type - what does the Standard say about this?
- From: Hallvard B Furuseth <h.b.furuseth@xxxxxxxxxxx>
- Date: Wed, 05 Nov 2008 19:57:48 +0100
Stephan Beal writes:
Doh, i spoke to soon:
http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html
Says:
"In C99, it is illegal to create an alias of a different type than the
original. This is often refered to as the strict aliasing rule."
Not quite. What is illegal, with some exceptions, is to access an
object (such as the object the pointer points at) thorugh a different
type than it was a created with. In Standardese, its "effective type".
But you can cast pointers back and forth, as long as you don't break
alignment requirements.
One such exception is to access equivalent initial members of structs
that are union members. So that's one formally valid way _if_ you know
all the "subtypes" of your base type: Stuff them all into a union, then
pass that union around. Don't make the base type a struct member,
instead do
#define BASE_STRUCT_BODY(prefix) \
int prefix##_i, prefix##_j
struct base_struct { BASE_STRUCT_BODY(bs); };
struct other_struct { BASE_STRUCT_BODY(os); other members; };
The prefix is only necessary if you want different member names in
different structs.
It's not really clear to me what else the standard allows though. A
compiler's users would be kind of annoyed if sockets didn't work, as
Antoninus suggests. OTOH if you are worrying about formal rather than
practical examples that's not enough. Besides, the socket interface
could use implementation-specific tricks to disable optimizations what
would break sockets.
One (or the?) point of the aliasing rules is to enable optimizations.
If you access an object of type T and then call a function which the
compiler knows does not access type T, nor call a function which does,
nor use one of the exceptions, the compiler knows that it can move the
access to the T object past the function call. One trick to protect
your code from that is to keep the accesses through different types in
different source files. However that can get defeated by "link-time
optimizations".
Anyway, here are the relevant parts from C99 - with examples.
6.5.2.3 Structure and union members
5 One special guarantee is made in order to simplify the use of unions:
if a union contains several structures that share a common initial
sequence (see below), and if the union object currently contains one
of these structures, it is permitted to inspect the common initial
part of any of them anywhere that a declaration of the complete type
of the union is visible. Two structures share a common initial
sequence if corresponding members have compatible types (and, for
bit-fields, the same widths) for a sequence of one or more initial
members.
6 EXAMPLE 1 If f is a function returning a structure or union, and x
is a member of that structure or union, f().x is a valid postfix
expression but is not an lvalue.
7 EXAMPLE 2 In:
struct s { int i; const int ci; };
struct s s;
const struct s cs;
volatile struct s vs;
the various members have the types:
s.i int
s.ci const int
cs.i const int
cs.ci const int
vs.i volatile int
vs.ci volatile const int
8 EXAMPLE 3 The following is a valid fragment:
union {
struct {
int alltypes;
} n;
struct {
int type;
int intnode;
} ni;
struct {
int type;
double doublenode;
} nf;
} u;
u.nf.type = 1;
u.nf.doublenode = 3.14;
/* ... */
if (u.n.alltypes == 1)
if (sin(u.nf.doublenode) == 0.0)
/* ... */
The following is not a valid fragment (because the union type is not
visible within function f):
struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 * p1, struct t2 * p2)
{
if (p1->m < 0)
p2->m = -p2->m;
return p1->m;
}
int g()
{
union {
struct t1 s1;
struct t2 s2;
} u;
/* ... */
return f(&u.s1, &u.s2);
}
And the basic rules:
6.5 Expressions
6 The effective type of an object for an access to its stored value is
the declared type of the object, if any.[72] 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.
7 An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:[73]
- 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.
Footnotes:
72) Allocated objects have no declared type.
73) The intent of this list is to specify those circumstances in
which an object may or may not be aliased.
--
Hallvard
.
- Follow-Ups:
- Re: Pointer to "base" type - what does the Standard say about this?
- From: Stephan Beal
- Re: Pointer to "base" type - what does the Standard say about this?
- References:
- Pointer to "base" type - what does the Standard say about this?
- From: Stephan Beal
- Re: Pointer to "base" type - what does the Standard say about this?
- From: Antoninus Twink
- Re: Pointer to "base" type - what does the Standard say about this?
- From: Stephan Beal
- Re: Pointer to "base" type - what does the Standard say about this?
- From: Stephan Beal
- Pointer to "base" type - what does the Standard say about this?
- Prev by Date: Re: replace string
- Next by Date: Re: Pointer to "base" type - what does the Standard say about this?
- Previous by thread: Re: Pointer to "base" type - what does the Standard say about this?
- Next by thread: Re: Pointer to "base" type - what does the Standard say about this?
- Index(es):
Relevant Pages
|