Topic: Rebinding references (was: Guru of the Week #22: Object Lifetimes)
Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1997/11/17 Raw View
On 05 Nov 97 13:43:03 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
>
>|> After the function is compiled, it is
>|> impossible to change its behavior - clients only can call it.
>
>Note well that I specified that the deduction is only possible for
>inline functions.
I admit I have overlooked this. But see below...
>
>|> Therefore how can it be possible for a compiler to *automatically*
>|> omit range checks in situations like
>|>
>|> for ( unsigned i=0; i<nent; i++ )
>|> data[i].f();
>|>
>|> but OTOH having it in situations like
>|>
>|> void f( unsigned i ) {
>|> data[i].f();
>|> }
>
>If the function is inline, there is no reason for the compiler to
>generate the same code in each context. (In fact, this is the major
>advantage of inline functions.) In the case of the loop, hoisting
>constant expressions out of the loop is standard practice even today.
>Hoisting a bounds check out of the loop is a little more complicated,
>but certainly not rocket science.
>
I thought an inline function must exhibit the same behavior than the
same function written not inline. So if a user writes
void g( unsigned nent ) {
for ( unsigned i=0; i<nent; i++ )
data[i].f();
}
he/she should know exactly what the function is doing by looking at
the function's implementation (not the declaration). For me, I want to
know whether operator [] *will do* or *will not do* range checks.
Further, the compiler may inline a function or not - it is not
required to inline it even if it is declared inline - what makes the
matter even more complicated.
AND - virtual functions are never inlined when called via pointers or
references, but in a derived class one is not required to use the
virtual keyword. SO - do I have to look at base classes to figure out
the semantics of a function's implementation ...? I definitely hope
this is not so.
------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/11/18 Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:
|> I thought an inline function must exhibit the same behavior than the
|> same function written not inline.
The same observable behavior. Observable behavior involves the system
calls resulting from input and output, accessing a volatible variable,
etc.
|> So if a user writes
|>
|> void g( unsigned nent ) {
|> for ( unsigned i=0; i<nent; i++ )
|> data[i].f();
|> }
|>
|> he/she should know exactly what the function is doing by looking at
|> the function's implementation (not the declaration). For me, I want to
|> know whether operator [] *will do* or *will not do* range checks.
But you can't, even today. At least, not as long as doing range checks
is not observable behavior. (You could know if, for example, you
declared the array bounds volatile. Or if you added an output statement
to the range check function -- although even then, the compiler could do
the output, but not the check.)
|> Further, the compiler may inline a function or not - it is not
|> required to inline it even if it is declared inline - what makes the
|> matter even more complicated.
|> AND - virtual functions are never inlined when called via pointers or
|> references, but in a derived class one is not required to use the
|> virtual keyword. SO - do I have to look at base classes to figure out
|> the semantics of a function's implementation ...? I definitely hope
|> this is not so.
What semantics? The semantics of a function define the observable
behavior of an abstract machine. The compiler is required to generate
code which results in the same observable behavior.
The semantics of a bounds checked array access is e.g. abort if the
index is out of range, and do the access if it isn't. The compiler can
generate any code it wishes in order to obtain those semantics. In
particular, if it can prove that the index will always be in range, it
can simply generate the access (and similarly, if it can prove that the
index will always be out of range, it can generate a call to abort
directly, without a test.)
Note that in the above, if the compiler cannot prove that calling f() on
the array element has no observable behavior when followed by an
abort(), it must ensure that f() is called for all in range elements
before aborting -- typically, that means two copies of the loop, one
with range checking (used when nent is out of bounds), and one without.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/11/07 Raw View
Paul D. DeRocco wrote:
>
> John Calcote wrote:
[...]
> > In fact, compiler writers would have to actually go out of their way to
> > implement a compiler which actually accesses a value at the "bad" address.
>
> Exactly. What would it _do_ with that address? Read it or write
> it?
Write the invalid selector part of an 16:16 or 16:32 80x86 pointer
into a segment register. This is enough to give a processor exception
- even if you never access that memory.
OTOH, if you don't access that memory, there's no point to load
the segment register (just waste of time).
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/11/07 Raw View
Paul D. DeRocco wrote:
[...]
> This doesn't mean that such dereferencing necessarily causes
> problems. For instance, *(int*)0 "works" in most MS-DOS
> programs, either accessing absolute memory location 0 or offset
> 0 within the data segment, depending upon the memory model.
Indeed, (void**)0 is actually useful under DOS (real mode/large
memory model assumed, and representation of null pointer with 0):
It returns a pointer to the interrupt table, so that f.ex.
*(void**)0 gives the address of the division by zero handler.
[...]
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1997/11/04 Raw View
On 29 Oct 97 07:59:46 GMT, Valentin Bonnard <bonnardv@pratique.fr>
wrote:
>> IMHO, all languages that use range checks
>> automatically and implicitely have a design flaw.
>
>I think that you'll get many comments on that.
>The problem is not with having range checks implicitly,
>it's with not having a way to disable them of easilly.
You are correct, of course. If I can disable the check in situations
where it is not necessary I am happy. Do you know of a language where
I can do that? I don't.
All I wanted to say was that I like C++ for not doing a range check on
every access to a built in array. But I *can* have more control if I
use things like vector etc.
------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1997/11/04 Raw View
On 29 Oct 97 11:54:53 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
>|>
>|> for ( unsigned i=0; i<nent; i++ )
>|> data[i].f(); // assuming X has member function f
>|>
>|> AND I DON'T WANT RANGE CHECKS TO OCCUR HERE, because I *know* that the
>|> loop will work. IMHO, all languages that use range checks
>|> automatically and implicitely have a design flaw.
>
>On the other hand, this is typically a case where the range checks don't
>cost anything, since the compiler will do it once, before the start of
>the loop, and not each time through the loop.
>
>Of course, to do this, the compiler must understand the semantics of the
>range check. It can do this in two ways: the range check is part of the
>language, so the compiler automatically knows the semantics, or it is
>able to deduce the semantics from the user code. Obviously, the latter
>is more difficult (but if we are talking about traditional range
>checking in an inline operator[], I would expect most compilers should
>be able to do it).
I think a compiler cannot deduce semantics from user code. When it
compiles operator [], it must decide about using range checks, or not
(to stick to our example). After the function is compiled, it is
impossible to change its behavior - clients only can call it.
Therefore how can it be possible for a compiler to *automatically*
omit range checks in situations like
for ( unsigned i=0; i<nent; i++ )
data[i].f();
but OTOH having it in situations like
void f( unsigned i ) {
data[i].f();
}
------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/11/04 Raw View
Clive D.W. Feather <clive@on-the-train.demon.co.uk> writes:
> In article <344E71B6.446B9B3D@pratique.fr>, Valentin Bonnard
> <bonnardv@pratique.fr> writes
> >(ANSI C)
> >I have never been able to understand what alignement was...
> Alignment is defined in, IIRC, subclause 3.1 of the ISO Standard.
> Certainly somewhere in clause 3 (definitions).
>
> Alignment is the requirement that addresses of some type be a multiple
> of some number defined for that type. It is possible to show that
> sizeof(type) must be a multiple of the alignment of the type.
How can an addres be a multiple of something ?
An address is not a member.
> It's there mainly for dealing with pointer casts.
To have the concept alignement just to say that some
casts A* to B* can be reversed by B* to A* seems strange
to me.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/11/04 Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:
>Valentin Bonnard <bonnardv@pratique.fr> wrote:
>
>>[someone wrote:]
>>> IMHO, all languages that use range checks
>>> automatically and implicitely have a design flaw.
>>
>>I think that you'll get many comments on that.
>>The problem is not with having range checks implicitly,
>>it's with not having a way to disable them of easilly.
>
>You are correct, of course. If I can disable the check in situations
>where it is not necessary I am happy. Do you know of a language where
>I can do that? I don't.
You can do it in Ada. Ada includes a standard pragma for doing this.
For example:
-- suppress all index checks on accesses to the array `foo'
pragma suppress(index_checks, foo);
begin
-- suppress all index checks in this begin-end block
pragma suppress(index_checks);
...
end;
See section 11.5 in the Ada 95 language reference manual.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/11/04 Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:
>kanze@gabi-soft.fr (J. Kanze) wrote:
>
>>|> [someone wrote:]
>>|>
>>|> for ( unsigned i=0; i<nent; i++ )
>>|> data[i].f(); // assuming X has member function f
>>|>
>>|> AND I DON'T WANT RANGE CHECKS TO OCCUR HERE, because I *know* that the
>>|> loop will work. IMHO, all languages that use range checks
>>|> automatically and implicitely have a design flaw.
>>
>>On the other hand, this is typically a case where the range checks don't
>>cost anything, since the compiler will do it once, before the start of
>>the loop, and not each time through the loop.
>>
>>Of course, to do this, the compiler must understand the semantics of the
>>range check. It can do this in two ways: the range check is part of the
>>language, so the compiler automatically knows the semantics, or it is
>>able to deduce the semantics from the user code. Obviously, the latter
>>is more difficult (but if we are talking about traditional range
>>checking in an inline operator[], I would expect most compilers should
>>be able to do it).
>
>I think a compiler cannot deduce semantics from user code. When it
>compiles operator [], it must decide about using range checks, or not
>(to stick to our example). After the function is compiled, it is
>impossible to change its behavior - clients only can call it.
>Therefore how can it be possible for a compiler to *automatically*
>omit range checks in situations like
>
> for ( unsigned i=0; i<nent; i++ )
> data[i].f();
>
>but OTOH having it in situations like
>
> void f( unsigned i ) {
> data[i].f();
> }
I don't agree with Kanze's expectation that "most compilers should
be able to do it", but it is certainly quite feasible to do.
For example, the compiler can generate two different versions
of the code, one with range checks and one without; for each
call, it determines whether the range checks are needed, and
accordingly calls the appropriate version.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1997/11/05 Raw View
In article <345CCA07.5F2D@pratique.fr>, Valentin Bonnard
<bonnardv@pratique.fr> writes
>> Alignment is defined in, IIRC, subclause 3.1 of the ISO Standard.
>> Certainly somewhere in clause 3 (definitions).
>>
>> Alignment is the requirement that addresses of some type be a multiple
>> of some number defined for that type. It is possible to show that
>> sizeof(type) must be a multiple of the alignment of the type.
>
>How can an addres be a multiple of something ?
>An address is not a member.
Assuming you mean "number"; in most architectures, addresses are
numbers. This terminology treats them that way.
>> It's there mainly for dealing with pointer casts.
>To have the concept alignement just to say that some
>casts A* to B* can be reversed by B* to A* seems strange
>to me.
But it's not just that case. What the Standard allows is complicated
enough that alignment is the right way to explain it.
--
Clive D.W. Feather | Director of Software Development | Home email:
Tel: +44 181 371 1138 | Demon Internet Ltd. | <clive@davros.org>
Fax: +44 181 371 1037 | <clive@demon.net> |
Written on my laptop; please observe the Reply-To address |
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/11/05 Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:
|> On 29 Oct 97 11:54:53 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
|>
|> >|>
|> >|> for ( unsigned i=0; i<nent; i++ )
|> >|> data[i].f(); // assuming X has member function f
|> >|>
|> >|> AND I DON'T WANT RANGE CHECKS TO OCCUR HERE, because I *know* that the
|> >|> loop will work. IMHO, all languages that use range checks
|> >|> automatically and implicitely have a design flaw.
|> >
|> >On the other hand, this is typically a case where the range checks don't
|> >cost anything, since the compiler will do it once, before the start of
|> >the loop, and not each time through the loop.
|> >
|> >Of course, to do this, the compiler must understand the semantics of the
|> >range check. It can do this in two ways: the range check is part of the
|> >language, so the compiler automatically knows the semantics, or it is
|> >able to deduce the semantics from the user code. Obviously, the latter
|> >is more difficult (but if we are talking about traditional range
|> >checking in an inline operator[], I would expect most compilers should
|> >be able to do it).
|>
|> I think a compiler cannot deduce semantics from user code. When it
|> compiles operator [], it must decide about using range checks, or not
|> (to stick to our example).
If the range checks are a built-in part of the language (as with Ada,
the Modula family, and others), then it knows the semantics implicitly,
it doesn't have to deduce them. This is, IMHO, the strongest argument
for having range checks as part of the language -- performance. In such
cases, it is nice to have a pragma or something to turn them off in
specific instances where you can prove the index in bounds, but the
compiler cannot, and profiling has shown a bottleneck.
|> After the function is compiled, it is
|> impossible to change its behavior - clients only can call it.
Note well that I specified that the deduction is only possible for
inline functions. An inline function is "compiled" inline, each time it
is invoked. In this case, the resulting code is directly in the loop --
comparing i with upperBound each time through the loop. It is not
difficult to determine that a single test before the beginning of the
loop would be logically equivalent. (There are some difficulties in
maintaining the exact semantics: with a test each time through the loop,
the loop will have been executed upperBound times before the error
occurs, and this behavior must be maintained.)
|> Therefore how can it be possible for a compiler to *automatically*
|> omit range checks in situations like
|>
|> for ( unsigned i=0; i<nent; i++ )
|> data[i].f();
|>
|> but OTOH having it in situations like
|>
|> void f( unsigned i ) {
|> data[i].f();
|> }
If the function is inline, there is no reason for the compiler to
generate the same code in each context. (In fact, this is the major
advantage of inline functions.) In the case of the loop, hoisting
constant expressions out of the loop is standard practice even today.
Hoisting a bounds check out of the loop is a little more complicated,
but certainly not rocket science.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/11/04 Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
|> J. Kanze wrote:
|> >
|> > As a simple example, in the expression p->staticFunction(), I know of no
|> > compiler which will generate accesses through p. But the standard is
|> > very explicit: p-> *must* be evaluated, and p must point to a valid
|> > object, or undefined behavior occurs.
|>
|> As a language lawyer, you are no doubt correct. But computers
|> aren't magic. Although the draft standard makes no promises, I
|> can't imagine in what way p->staticFunction() could cause a
|> problem, even if p is NULL, because mechanically it doesn't _do_
|> anything with p. Were the function virtual, then it would be
|> obvious why the result would be "undefined", since the typical
|> implementation would look _through_ the pointer to find out what
|> function to call, which will obvious fail if the pointer is
|> NULL.
In the simple case, yes. But imagine that p is in fact an expression,
which calls a function which has side effects. You do want to know
whether that function is called or not.
|> I think the only reason the standard requires that p be
|> evaluated in p->staticFunction() is so that nothing unexpected
|> happens (or stops happening) when a member function is changed
|> to static (or from static). Personally, I'm not convinced that's
|> the right choice, because I think that's not the sort of change
|> that's likely, given the intrinsically different semantics of
|> static and nonstatic member functions. In fact, I never use . or
|> -> to invoke static member functions anyway.
I'm not sure that the only motivation was possible changes, although
that was probably part of it. There is the simple fact that the
necessary information is not local -- you have to go looking for it.
(Note that this is NOT the case with sizeof.)
|> It would be different if it were possible to declare a static
|> virtual function, i.e., one that vectors through an object's
|> vtbl but has no this pointer.
Agreed. In this case, you would have no choice but to evaluate the
expression.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/31 Raw View
Esa Pulkkinen <esap@cs.tut.fi> writes:
|> > Esa Pulkkinen <esap@cs.tut.fi> writes:
|> > |> So it's not undefined, but the typeid expression throws the bad_typeid
|> > |> exception *if the expression is an lvalue whose type is a polymorphic
|> > |> class type*. Otherwise [expr.typeid]/3 applies, and the expression
|> > |> given to typeid is not evaluated:
|> [SNIP]
|>
|> kanze@gabi-soft.fr (J. Kanze) writes:
|> > I don't like that. In sum: if the expression is an "lvalue expression
|> > whose type is a polymorphic class type", the expression is evaluated;
|> > otherwise it is not. Thus, "typeid( *((MyClass*)0) )" is undefined
|> > behavior if MyClass has any virtual functions, but defined otherwise.
|>
|> Actually, I think you misunderstood what I was trying to say. My
|> interpretation is that "typeid( *((MyClass*)0) )" is *never* undefined.
|> Instead, if the expression is of polymorphic class type (i.e. MyClass
|> has virtual functions), then the typeid throws an exception, and so it's
|> _not_ undefined. Note the last sentence of [expr.typeid]/3 I quoted:
|>
|> > |> If the lvalue expression is obtained by applying the unary *
|> > |> operator to a pointer8) and the pointer is a null pointer value
|> > |> (_conv.ptr_), the typeid expression throws the bad_typeid exception
|> > |> (_lib.bad.typeid_).
|>
|> Since it's explicitly said it throws an exception, it can't be
|> undefined, can it? Or am I missing something here?
You're right, I think. For this specific case: the expression is
evaluated, but there is a special case for dereferencing a null
pointer.
|> > Worse, if "f" is a function returning a "MyClass*" (pointer to a valid
|> > object), then in the expression "typeid( *f() )", whether "f" is called
|> > (and thus, its side effects take place) depends on whether "MyClass" has
|> > virtual functions or not.
|>
|> Yes, this is a problem.
|>
|> > In this respect, since for obvious reasons, the expression in a typeid
|> > must be evaluated in certain circumstances, IMHO, it should be evaluated
|> > in all circumstances.
|>
|> Agreed. That would be clearer. (But then my polymorphity-test wouldn't
|> work and I couldn't use it to test objects before giving them to
|> dynamic_cast, could I? :)
No, your polymorphity test wouldn't work:-).
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/29 Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:
|> On 26 Oct 97 08:43:18 GMT, Valentin Bonnard <bonnardv@pratique.fr>
|> wrote:
|>
|> >
|> >Bound checking is common in other languages. For
|> >traditionnal (?) reasons, it is rare in C/C++.
|> >
|>
|> No! Look at an arbitrary container class. Usually you have something
|> like this (details ommited):
|>
|> class Container_for_X {
|> X* data; // internal representation as
|> array of X-Objects
|> unsigned nent; // number of elements
|>
|> /** .. other stuff ... **/
|>
|>
|>
|> We assume now that nent always has the correct number of elements in
|> the internal representation. Therefore, in a member function of
|> Container_for_X, one can write
|>
|> for ( unsigned i=0; i<nent; i++ )
|> data[i].f(); // assuming X has member function f
|>
|> AND I DON'T WANT RANGE CHECKS TO OCCUR HERE, because I *know* that the
|> loop will work. IMHO, all languages that use range checks
|> automatically and implicitely have a design flaw.
On the other hand, this is typically a case where the range checks don't
cost anything, since the compiler will do it once, before the start of
the loop, and not each time through the loop.
Of course, to do this, the compiler must understand the semantics of the
range check. It can do this in two ways: the range check is part of the
language, so the compiler automatically knows the semantics, or it is
able to deduce the semantics from the user code. Obviously, the latter
is more difficult (but if we are talking about traditional range
checking in an inline operator[], I would expect most compilers should
be able to do it).
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bparker@mailbox.uq.edu.au (Brian Parker)
Date: 1997/10/30 Raw View
On 29 Oct 97 11:48:36 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
>...
>Sort of. The C standard (6.5.2.1) says: "There may therefore be unnamed
>padding within a structure object, but not at its beginning, as
>necessary to achieve the appropriate alignment." So "alignment" is the
>excuse. On the other hand, the standard says nothing about what is
>meant be "appropriate alignment", so the excuse is somewhat vacuous --
>an implementation is free to say that aligning all struct's on a 128
>byte boundayr is appropriate, even in the absense of any hardware
>motivation.
However, 3.9 Para 4 states that alignment requirements are
"implementation defined", so an implementation could specify a 128
byte alignment but having done so must document and use it
consistently and cannot arbitrarily add padding not needed to meet the
specified alignment. This is an important guarantee of the C++ memory
model- with it one can predict the exact layout of a POD- and I agree
that the CD2 is not as clear as it should be on this issue and so, I
think, the draft needs an additional note clarifying this e.g. [Note:
only the minimum padding to meet specified alignment requirements is
allowed.]
,Brian Parker.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Esa Pulkkinen <esap@cs.tut.fi>
Date: 1997/10/30 Raw View
> Esa Pulkkinen <esap@cs.tut.fi> writes:
> |> So it's not undefined, but the typeid expression throws the bad_typeid
> |> exception *if the expression is an lvalue whose type is a polymorphic
> |> class type*. Otherwise [expr.typeid]/3 applies, and the expression
> |> given to typeid is not evaluated:
[SNIP]
kanze@gabi-soft.fr (J. Kanze) writes:
> I don't like that. In sum: if the expression is an "lvalue expression
> whose type is a polymorphic class type", the expression is evaluated;
> otherwise it is not. Thus, "typeid( *((MyClass*)0) )" is undefined
> behavior if MyClass has any virtual functions, but defined otherwise.
Actually, I think you misunderstood what I was trying to say. My
interpretation is that "typeid( *((MyClass*)0) )" is *never* undefined.
Instead, if the expression is of polymorphic class type (i.e. MyClass
has virtual functions), then the typeid throws an exception, and so it's
_not_ undefined. Note the last sentence of [expr.typeid]/3 I quoted:
> |> If the lvalue expression is obtained by applying the unary *
> |> operator to a pointer8) and the pointer is a null pointer value
> |> (_conv.ptr_), the typeid expression throws the bad_typeid exception
> |> (_lib.bad.typeid_).
Since it's explicitly said it throws an exception, it can't be
undefined, can it? Or am I missing something here?
> Worse, if "f" is a function returning a "MyClass*" (pointer to a valid
> object), then in the expression "typeid( *f() )", whether "f" is called
> (and thus, its side effects take place) depends on whether "MyClass" has
> virtual functions or not.
Yes, this is a problem.
> In this respect, since for obvious reasons, the expression in a typeid
> must be evaluated in certain circumstances, IMHO, it should be evaluated
> in all circumstances.
Agreed. That would be clearer. (But then my polymorphity-test wouldn't
work and I couldn't use it to test objects before giving them to
dynamic_cast, could I? :)
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: esap@cs.tut.fi | everywhere with class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bparker@mailbox.uq.edu.au (Brian Parker)
Date: 1997/10/30 Raw View
On 28 Oct 97 14:22:01 GMT, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
wrote:
>"typeid( *(int*)0 )" is fine.
>The expression in a typeid is evaluated if and only if the expression
>is an lvalue of a polymorphic type. See 5.2.8 [expr.typeid].
>(A "polymorphic" type is one which has at least one virtual function.)
Is typeid() therefore a constant expression when used on a
non-polymorphic type (like sizeof)?
,Brian Parker.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/30 Raw View
bparker@mailbox.uq.edu.au (Brian Parker) writes:
>On 28 Oct 97 14:22:01 GMT, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
>wrote:
>
>>"typeid( *(int*)0 )" is fine.
>>The expression in a typeid is evaluated if and only if the expression
>>is an lvalue of a polymorphic type. See 5.2.8 [expr.typeid].
>>(A "polymorphic" type is one which has at least one virtual function.)
>
>Is typeid() therefore a constant expression when used on a
>non-polymorphic type (like sizeof)?
No. A compiler is allowed to evaluate it at compile time, but it is
not a reference constant expression in the sense of 5.19 [expr.const],
so for example you can't pass it as a template parameter.
template <const type_info &ti> class Foo {};
Foo<typeid(0)> foo; // ERROR - typeid(0) is not a constant
// expression
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/28 Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:
|> Bill Wade <bill.wade@stoner.com> writes:
|>
|> > Valentin Bonnard <bonnardv@pratique.fr> wrote in article
|> > <344E71B6.446B9B3D@pratique.fr>...
|> > > [Note : cross-posted to comp.std.c and comp.std.c++.]
|> >
|> > > What would happen if we remove all sentences about alignement in both
|> > > std ? (a clarification, I would guess)
|> >
|> > Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to be
|> > different from sizeof(T1)+sizeof(T2).
|>
|> Why an 'excuse' ? Nothing is required for sizeof struct, not even for
|> sizeof union { char c; } which could be 8.
|>
|> Alignement might be a usefull concept for textbooks (well, it _might_
|> be, I am not sure that it's a good idea to speak about that), but not
|> for the standard. OTOH the standard has the concept of linkage, and I
|> have yet to see it in a textbook... it means that the standard may
|> use other concepts than most programmers.
This is true, and in a certain sense, the use of "alignment" in the
standard isn't exactly the same as what one normally uses ("undefined
behavior" vs. bus error or whatever). The meaning is close enough,
however, to aid understanding, and IMHO, renders the standard somewhat
clearer.
We could just as easily speak of "frombouzelment", with no loss of
precision, since within the standard, the definition is that given by
the standard. But the intuitive meaning of "alignment" is close enough
to the meaning within the standard for most people to understand the
rationale as well, and thus better or more easily understand what the
standard is trying to say.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1997/10/28 Raw View
On 26 Oct 97 08:43:18 GMT, Valentin Bonnard <bonnardv@pratique.fr>
wrote:
>
>Bound checking is common in other languages. For
>traditionnal (?) reasons, it is rare in C/C++.
>
No! Look at an arbitrary container class. Usually you have something
like this (details ommited):
class Container_for_X {
X* data; // internal representation as
array of X-Objects
unsigned nent; // number of elements
/** .. other stuff ... **/
We assume now that nent always has the correct number of elements in
the internal representation. Therefore, in a member function of
Container_for_X, one can write
for ( unsigned i=0; i<nent; i++ )
data[i].f(); // assuming X has member function f
AND I DON'T WANT RANGE CHECKS TO OCCUR HERE, because I *know* that the
loop will work. IMHO, all languages that use range checks
automatically and implicitely have a design flaw.
Note: C++ lets you have the check, but does not enforce it.
------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/28 Raw View
In comp.std.c++ Paul D. DeRocco <pderocco@ix.netcom.com> wrote:
: J. Kanze wrote:
: >
: > From a standards point of view, sizeof(*p) differs from &(*p) in that in
: > the first, the (sub-)expression *p is not evaluated, whereas in the
: > second, it is.
: No, *p isn't evaluated, p is. What does it mean to "evaluate" *p
: but to compute its value, which would mean reading the memory
: location pointed to? I'll bet there isn't a single compiler out
: there that reads the memory location pointed to by p when you
: write &*p or &(*p).
That's not the point. In the expression *p=0, the lvalue *p is
"evaluated," i.e., p is "dereferenced," even though the expression *p
is never converted to an rvalue, i.e., we never read the memory
location pointed to by p. Similarly, since the address-of operator
(unary &) takes an lvalue (just like the lefthand side of the
assignment operator), &*p involves evaluating *p as an lvalue, but not
converting it to an rvalue.
So much for what the standard says. There remains the question: Why
not, for the sake of mnemonic and pedagogical efficiency, treat unary
& and unary * as exact inverses? Suppose that we have a pointer
valued expression <exp>. If is value is suitable for dereferencing
then <exp> and &*<exp> have exactly the same well-defined value. If
its value is not suitable even for comparisions (e.g., it is the name
of a pointer variable that happens to be dangling) then (AFIK) the
evaluation of either <exp> or &*<exp> provokes undefined behavior.
So, as I understand it, the only cases where there is an issue are the
cases where the value of <exp> is null or <exp> points one past the
end of an array. Is there any reason not to stipulate that <exp> and
&*<exp> have the same value in such cases?
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/28 Raw View
kanze@gabi-soft.fr (J. Kanze) writes:
>FWIW: I am not sure whether the expression in a typeid is supposed to be
>evaluated or not. In the absense of a specific exception (as with
>sizeof), I would suppose that it should, and that expressions like
>"typeid( *(int*)0 )" result in undefined behavior.
"typeid( *(int*)0 )" is fine.
The expression in a typeid is evaluated if and only if the expression
is an lvalue of a polymorphic type. See 5.2.8 [expr.typeid].
(A "polymorphic" type is one which has at least one virtual function.)
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Esa Pulkkinen <esap@cs.tut.fi>
Date: 1997/10/28 Raw View
kanze@gabi-soft.fr (J. Kanze) writes:
> FWIW: I am not sure whether the expression in a typeid is supposed to be
> evaluated or not. In the absense of a specific exception (as with
> sizeof), I would suppose that it should, and that expressions like
> "typeid( *(int*)0 )" result in undefined behavior.
Actually I think there is specific wording about this:
[expr.typeid]/2:
2 When typeid is applied to an lvalue expression whose type is a poly-
morphic class type (_class.virtual_), the result refers to a type_info
object representing the type of the most derived object
(_intro.object_) (that is, the dynamic type) to which the lvalue
refers. If the lvalue expression is obtained by applying the unary *
operator to a pointer8) and the pointer is a null pointer value
(_conv.ptr_), the typeid expression throws the bad_typeid exception
(_lib.bad.typeid_).
So it's not undefined, but the typeid expression throws the bad_typeid
exception *if the expression is an lvalue whose type is a polymorphic
class type*. Otherwise [expr.typeid]/3 applies, and the expression
given to typeid is not evaluated:
3 When typeid is applied to an expression other than an lvalue of a
polymorphic class type, the result refers to a type_info object repre-
senting the static type of the expression.
[...]
The expression is not evaluated.
Note in [expr.typeid]/2 (dealing with an expression that is an lvalue of
a polymorphic class type) it doesn't say the expression is not evaluated
(So I guess that means the expression is evaluated). So (as a
semi-practical application) I think this (combined with [expr.typeid]/3)
means that you can check whether an expression is of "a polymorphic
class type" using typeid:
template <class T>
bool is_polymorphic(const T& x)
{
bool polymorphic=false;
typeid( ( (polymorphic = true), x ) );
return polymorphic;
}
Seems to work with egcs-2.90.12 at least.
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: esap@cs.tut.fi | everywhere with class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/10/28 Raw View
J. Kanze <kanze@gabi-soft.fr> wrote in article
<m3lnzf5w0g.fsf@gabi-soft.fr>...
> "Bill Wade" <bill.wade@stoner.com> writes:
> |>
> |> Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to
be
> |> different from sizeof(T1)+sizeof(T2).
>
> What does "no excuse" mean in this context? The standard explicitly
> allows padding anywhere in a struct except at the beginning -- the
> implementation is not required to justify the padding. (Of course, an
> implementation which threw in a couple of KB each time, just for the fun
> of it, would probably not sell very well, conforming or not.)
As far as I can tell padding anywhere in C++ POD is allowed only for
alignment purposes. I don't see any wording that says "padding is allowed
only for alignment purposes," but every statement that allows padding seems
to include alignment verbage, so there is a strong implication.
In C++ CD2 I see (9.2 para 12) "Implementation alignment requirements
might
cause two adjacent members not to be allocated immediately after each
other ... [ other comments that apply only to non-POD types ]" Paragraph
17 also allows padding in POD structs, but only for alignment purposes.
This gives implementors the "alignment excuse" for padding between POD
members. I don't see any other "excuse" for padding in POD structures.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/29 Raw View
Martin Aupperle <1xx754.273x@compuserve.com> writes:
> On 26 Oct 97 08:43:18 GMT, Valentin Bonnard <bonnardv@pratique.fr>
> wrote:
>
> >Bound checking is common in other languages. For
> >traditionnal (?) reasons, it is rare in C/C++.
> IMHO, all languages that use range checks
> automatically and implicitely have a design flaw.
I think that you'll get many comments on that.
The problem is not with having range checks implicitly,
it's with not having a way to disable them of easilly.
> Note: C++ lets you have the check, but does not enforce it.
Yes, but few compilers actually implement the check (none
that I have used) and I am wondering why.
For example, I don't know any compiler which does bound
checking on built-in arrays; James Kanze knows one, but
I am not even sure if it still exists (the compiler, not
James).
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/29 Raw View
Esa Pulkkinen <esap@cs.tut.fi> writes:
|> kanze@gabi-soft.fr (J. Kanze) writes:
|>
|> > FWIW: I am not sure whether the expression in a typeid is supposed to be
|> > evaluated or not. In the absense of a specific exception (as with
|> > sizeof), I would suppose that it should, and that expressions like
|> > "typeid( *(int*)0 )" result in undefined behavior.
|>
|> Actually I think there is specific wording about this:
|> [expr.typeid]/2:
|>
|> 2 When typeid is applied to an lvalue expression whose type is a poly-
|> morphic class type (_class.virtual_), the result refers to a type_info
|> object representing the type of the most derived object
|> (_intro.object_) (that is, the dynamic type) to which the lvalue
|> refers. If the lvalue expression is obtained by applying the unary *
|> operator to a pointer8) and the pointer is a null pointer value
|> (_conv.ptr_), the typeid expression throws the bad_typeid exception
|> (_lib.bad.typeid_).
|>
|> So it's not undefined, but the typeid expression throws the bad_typeid
|> exception *if the expression is an lvalue whose type is a polymorphic
|> class type*. Otherwise [expr.typeid]/3 applies, and the expression
|> given to typeid is not evaluated:
|>
|> 3 When typeid is applied to an expression other than an lvalue of a
|> polymorphic class type, the result refers to a type_info object repre-
|> senting the static type of the expression.
|> [...]
|> The expression is not evaluated.
I don't like that. In sum: if the expression is an "lvalue expression
whose type is a polymorphic class type", the expression is evaluated;
otherwise it is not. Thus, "typeid( *((MyClass*)0) )" is undefined
behavior if MyClass has any virtual functions, but defined otherwise.
Worse, if "f" is a function returning a "MyClass*" (pointer to a valid
object), then in the expression "typeid( *f() )", whether "f" is called
(and thus, its side effects take place) depends on whether "MyClass" has
virtual functions or not.
This seems very counter intuitive to me. I do remember discussing this
very point with regards to "f()->staticFnc()" -- the decision was that
"f()" must be called, since it was to confusing if whether it was called
or not depended on whether the following function was static.
In this respect, since for obvious reasons, the expression in a typeid
must be evaluated in certain circumstances, IMHO, it should be evaluated
in all circumstances.
|> Note in [expr.typeid]/2 (dealing with an expression that is an lvalue of
|> a polymorphic class type) it doesn't say the expression is not evaluated
|> (So I guess that means the expression is evaluated). So (as a
|> semi-practical application) I think this (combined with [expr.typeid]/3)
|> means that you can check whether an expression is of "a polymorphic
|> class type" using typeid:
|>
|> template <class T>
|> bool is_polymorphic(const T& x)
|> {
|> bool polymorphic=false;
|> typeid( ( (polymorphic = true), x ) );
|> return polymorphic;
|> }
|>
|> Seems to work with egcs-2.90.12 at least.
Interesting. This is, of course, the obvious "implementation" -- the
compiler evaluates when it needs the information. However, I would
normally have thought that the absense of evaluation should be an
optimization. The compiler can (always) suppress the evaluation when it
can determine that a conforming program cannot tell (the evaluation has
no side effects).
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Clive D.W. Feather" <clive@on-the-train.demon.co.uk>
Date: 1997/10/29 Raw View
In article <344E71B6.446B9B3D@pratique.fr>, Valentin Bonnard
<bonnardv@pratique.fr> writes
>(ANSI C)
>>an address inappropriately aligned for the type of the object pointed to
>I have never been able to understand what alignement was... can anybody
>help me, or it is just a void statement (and the notion of alignement
>is just there to confuse people).
Alignment is defined in, IIRC, subclause 3.1 of the ISO Standard.
Certainly somewhere in clause 3 (definitions).
Alignment is the requirement that addresses of some type be a multiple
of some number defined for that type. It is possible to show that
sizeof(type) must be a multiple of the alignment of the type.
It's there mainly for dealing with pointer casts.
--
Clive D.W. Feather | Director of Software Development | Home email:
Tel: +44 181 371 1138 | Demon Internet Ltd. | <clive@davros.org>
Fax: +44 181 371 1037 | <clive@demon.net> |
Written on my laptop; please observe the Reply-To address |
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/29 Raw View
"Bill Wade" <bill.wade@stoner.com> writes:
|> J. Kanze <kanze@gabi-soft.fr> wrote in article
|> <m3lnzf5w0g.fsf@gabi-soft.fr>...
|> > "Bill Wade" <bill.wade@stoner.com> writes:
|> > |>
|> > |> Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to
|> be
|> > |> different from sizeof(T1)+sizeof(T2).
|> >
|> > What does "no excuse" mean in this context? The standard explicitly
|> > allows padding anywhere in a struct except at the beginning -- the
|> > implementation is not required to justify the padding. (Of course, an
|> > implementation which threw in a couple of KB each time, just for the fun
|> > of it, would probably not sell very well, conforming or not.)
|>
|> As far as I can tell padding anywhere in C++ POD is allowed only for
|> alignment purposes. I don't see any wording that says "padding is allowed
|> only for alignment purposes," but every statement that allows padding seems
|> to include alignment verbage, so there is a strong implication.
|>
|> In C++ CD2 I see (9.2 para 12) "Implementation alignment requirements
|> might
|> cause two adjacent members not to be allocated immediately after each
|> other ... [ other comments that apply only to non-POD types ]" Paragraph
|> 17 also allows padding in POD structs, but only for alignment purposes.
|>
|> This gives implementors the "alignment excuse" for padding between POD
|> members. I don't see any other "excuse" for padding in POD structures.
Sort of. The C standard (6.5.2.1) says: "There may therefore be unnamed
padding within a structure object, but not at its beginning, as
necessary to achieve the appropriate alignment." So "alignment" is the
excuse. On the other hand, the standard says nothing about what is
meant be "appropriate alignment", so the excuse is somewhat vacuous --
an implementation is free to say that aligning all struct's on a 128
byte boundayr is appropriate, even in the absense of any hardware
motivation.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: jodle@bix.com (jodle)
Date: 1997/10/27 Raw View
J. Kanze (kanze@gabi-soft.fr) wrote:
: No. The two expressions which are exactly the same, according to the
: standard and K&R, are "*(array+i)" and "array[i]". In this case,
: "exactly the same" means that both dereference. (By definition,
: operator* dereferences.)
Yes. Both languages also allow expressions like:
int array[5];
int n = 3[array];
since *(array+3) is equivalent to *(3+array).
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/27 Raw View
Bill Wade <bill.wade@stoner.com> writes:
> Valentin Bonnard <bonnardv@pratique.fr> wrote in article
> <344E71B6.446B9B3D@pratique.fr>...
> > [Note : cross-posted to comp.std.c and comp.std.c++.]
>
> > What would happen if we remove all sentences about alignement in both
> > std ? (a clarification, I would guess)
>
> Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to be
> different from sizeof(T1)+sizeof(T2).
Why an 'excuse' ? Nothing is required for sizeof struct, not even for
sizeof union { char c; } which could be 8.
Alignement might be a usefull concept for textbooks (well, it _might_
be, I am not sure that it's a good idea to speak about that), but not
for the standard. OTOH the standard has the concept of linkage, and I
have yet to see it in a textbook... it means that the standard may
use other concepts than most programmers.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kaz@latte.cafe.net (Kaz)
Date: 1997/10/27 Raw View
In article <01bce0c7$9c735890$2864370a@janeway>,
Bill Wade <bill.wade@stoner.com> wrote:
>Valentin Bonnard <bonnardv@pratique.fr> wrote in article
><344E71B6.446B9B3D@pratique.fr>...
>> [Note : cross-posted to comp.std.c and comp.std.c++.]
>
>> What would happen if we remove all sentences about alignement in both
>> std ? (a clarification, I would guess)
>
>Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to be
>different from sizeof(T1)+sizeof(T2).
Not if unnamed padding at the end of a structure or union were still allowed
for whatever reason (one reason for padding is to make address calculations
more convenient. For example, the execution environment may have an efficient
means for accessing an array of structures that are 8 bytes wide, but a less
efficient way if they are 7 bytes wide).
The only reason for defending the use of alignment that I can see is that
without it, you cannot explain why
(char *) pointer_to_int + sizeof(int)
yields a valid pointer (other issues having been taken care of), and
(char *) pointer_to_int + 3
does not necessarily yield a valid pointer.
The following code is is undefined for reasons that can only be explained
using alignment:
{
int x[] = { 1, 2, 3, 4 };
char *pc = (char *) x + 1;
int *pi = (int *) pc;
int y = *pi;
}
In this snippet, the aliasing restrictions don't play a role, because object x
is being accessed with an lvalue that has an appopriate type. If pi were a
valid, aligned pointer, then *pi could well be used to access array x.
Is there any other rule that is violated here besides the requirement for a
pointer to be aligned for access to its pointed at type? It seems that only
the validity of the pointer is an issue. It, and nothing else, is the reason
why the behavior is undefined.
On the other hand
{
int x[] = { 1, 2, 3, 4 };
char *pc = (char *) x + sizeof(int);
int *pi = (int *) pc;
int y = *pi;
}
will initialize y with the value 2. It just has to work because the character
pointer was displaced by a number of bytes equivalent to the size of the
integer, that is, it was displace by an appropriate multiple of bytes.
And that brings us back to alignment.
The concept of alignment accounts both for the failure of the first, and the
success of the second. Can the distinction be made without referring to
alignment? To me, it seems like the answer is no. Hence alignment cannot be
surgically removed from the language without serious implications to the
correctness of existing programs.
--
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/10/28 Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote in article
<34515EBF.795E4DE4@ix.netcom.com>...
> Bill Wade wrote:
> >
> > You don't have the right to do it (3.10 para 15). Even without
alignment
> > restrictions the assignment is undefined.
>
> When they say "undefined", they mean that the standard doesn't
> define the result. But it's obstinate legalism to assume that
> the result is so intrinsically meaningless that the construct
> should be prohibited, in those cases where you know the
> underlying hardware structure. For that reason, I'd be pissed
> off, justifiably I believe, if a compiler wouldn't let me cast a
> long* to a short* and access through it. I do that sort of thing
> all the time in intentionally non-portable embedded code.
>
> > [ Bill writes obscure alignment restrictions ]
> [ Paul says that is silly (not his words)]
I'll agree that my example is silly. However assuming that 3.10[15] is
there only for alignment reasons is also wrong.
void Shrink(const long* src, short* dest, int n)
{
// Do this loop forward in case (char*)src == (char*)dest;
for(int i = 0; i < n; ++i)
dest[i] = src[i];
}
The comment shows the programmer making an invalid assumption. Because the
two pointers have incompatible types the compiler can assume (because of
3.10) that the arrays don't overlap and may rewrite the copy as
while(n--) dest[n] = src[n];
This may be faster on some machines, but won't do the same thing if src and
dest overlap.
Likewise given (assume sizeof short==2 and sizeof long==4 and all bits are
used).
void Foo()
{
long l = 0;
short* s = &l;
s[0] = 5;
s[1] = 23;
cout << l;
}
The above manipulations are common on PC's (a long is a graphics coordinate
consisting of a short x and a short y). However it is perfectly legal for
a compiler to change that to
void Foo()
{
cout << 0L;
}
I've used compilers that performed similar optimizations and they are legal
according to the standard (I admit I haven't seen them under windows).
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/28 Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
|> J. Kanze wrote:
|> >
|> > From a standards point of view, sizeof(*p) differs from &(*p) in that in
|> > the first, the (sub-)expression *p is not evaluated, whereas in the
|> > second, it is.
|>
|> No, *p isn't evaluated, p is. What does it mean to "evaluate" *p
|> but to compute its value, which would mean reading the memory
|> location pointed to? I'll bet there isn't a single compiler out
|> there that reads the memory location pointed to by p when you
|> write &*p or &(*p).
Two points: evaluating *p certainly doesn't mean that you have to read
any associated memory. Consider "*p = 0 ;", for example. And what any
particular compiler does is irrelevant to the question: the standard
says that evaluating *p is undefined behavior unless p points to a valid
object.
As a simple example, in the expression p->staticFunction(), I know of no
compiler which will generate accesses through p. But the standard is
very explicit: p-> *must* be evaluated, and p must point to a valid
object, or undefined behavior occurs.
FWIW: I am not sure whether the expression in a typeid is supposed to be
evaluated or not. In the absense of a specific exception (as with
sizeof), I would suppose that it should, and that expressions like
"typeid( *(int*)0 )" result in undefined behavior.
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/28 Raw View
"Bill Wade" <bill.wade@stoner.com> writes:
|> Valentin Bonnard <bonnardv@pratique.fr> wrote in article
|> <344E71B6.446B9B3D@pratique.fr>...
|> > [Note : cross-posted to comp.std.c and comp.std.c++.]
|>
|> > What would happen if we remove all sentences about alignement in both
|> > std ? (a clarification, I would guess)
|>
|> Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to be
|> different from sizeof(T1)+sizeof(T2).
What does "no excuse" mean in this context? The standard explicitly
allows padding anywhere in a struct except at the beginning -- the
implementation is not required to justify the padding. (Of course, an
implementation which threw in a couple of KB each time, just for the fun
of it, would probably not sell very well, conforming or not.)
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/24 Raw View
Fergus Henderson wrote:
>
> kaz@latte.cafe.net (Kaz) writes:
>
> >If all mentions of alignment were removed from the standard (without removing
> >the implied restrictions), you would merely lose certain concepts that are
> >very useful in machine-specific coding.
>
> Ah. The key phrase here is "without removing the implied restrictions".
> In that case, what is being suggested is just a change in wording.
So my real question is what are the implied restrictions ?
So far, the only idea I have seen is malloc/operator new/new statement
which return storage suitably aligned.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kaz@latte.cafe.net (Kaz)
Date: 1997/10/24 Raw View
In article <344F59F8.41C6@wizard.net>, James Kuyper <kuyper@wizard.net> wrote:
>Valentin Bonnard wrote:
>> What would happen if we remove all sentences about alignement in both
>> std ? (a clarification, I would guess)
>
>Conforming compilers could never make any useful assumptions about the
>alignment of a pointer. They would always need to include the slower
>code needed to work with with arbitrary alignments. On some machines,
>that code would necessarily be executed, even for properly aligned
>pointers.
I don't understand why this has to follow. Those compilers would continue to
ensure that all declared or dynamically allocated objects are placed on
properly aligned addresses. If the programer plays with pointers, the program
isn't portable anymore anyway. The standard only gives you the guarantee that
converting a pointer to a character type to some other object or incomplete
type and back results in the same pointer. It says nothing about the relative
alignments. All you have to say is that converting a pointer from one type to
another makes a potentially invalid pointer, unless the target is a pointer to
char (with special concessions for conversions between pointers to structures
and their first members, or pointers to unions and any of their members.)
Don't forget that there are compilers for the 80x86 architecture which
allocate objects on boundaries divisible by four (or some cases eight),
despite the fact that all objects have the same alignment restriction as a
character type; the concept of alignment doesn't even exist.
What about other languages? Does Pascal incorporate a notion of alignment? If
not, does it mean that Pascal implementations generate code that accesses long
integers at arbitrary addresses by sucking bytes?
--
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/10/24 Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote in article
> > long l = 4;
> > short* s = (short*) l;
> > int i = s; // can't do that !
>
> I assume you mean't *s in the last line.
And I assume he meant &l in the second to last line.
> You do have a right to do it. You get the contents of the first
> word occupied by l. It's not the sort of thing you'd ever do
> unless you knew the machine you were working on, since the
> result would differ between a LE and BE machine.
You don't have the right to do it (3.10 para 15). Even without alignment
restrictions the assignment is undefined.
> What's certain,
> though, is that since a short is no longer than a long, casting
> a valid long pointer to a short pointer won't create a pointer
> that violates the alignment requirements of short.
As far as I can tell the standard allows
sizeof(short) == 3;
sizeof(long) == 5;
union u { short s; long l; };
sizeof(u) == 15;
with alignment restrictions equal to size in each case. Such an
implementation would mean that the code segment above violated the
alignment restrictions of short.
The probable intent of the code above can be more portably written as
long l = 4;
short s;
memcpy(&s, &l, sizeof(short));
int i = s;
Of course the value of i will depend on the representations of the various
types. My code probably is not portable if there are bit patterns in the
object representation for 's' which are invalid for shorts. However such
implementations are probably about as common as implementations where
sizeof(u) == 15.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kaz@latte.cafe.net (Kaz)
Date: 1997/10/24 Raw View
In article <62o1en$9em@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> wrote:
>"Jack Klein" <jackklein@worldnet.att.net> writes:
>
>>Valentin Bonnard <bonnardv@pratique.fr> wrote in article
>>> [Note : cross-posted to comp.std.c and comp.std.c++.]
>>>
>>> >Footnote 42 asserts that: (ANSI C)
>>> >an address inappropriately aligned for the type of the object pointed to
>>>
>>> I have never been able to understand what alignement was... can anybody
>>> help me, or it is just a void statement (and the notion of alignement
>>> is just there to confuse people).
>>>
>>> (Note: if you answer me, please make sure that your answer is justified
>>> by the standard.)
>>>
>>> What would happen if we remove all sentences about alignement in both
>>> std ? (a clarification, I would guess)
>>
>>There are some processors which will not physically address
>>certain size variables on an improper alignment.
>
>We know that. But you didn't answer Valentin Bonnard's questions.
>
>First, with regard to what would happen if you remove all sentences
>about alignment: (1) existing compilers would become non-conforming
>and (2) conforming compilers for the aforementioned processors would
>often have to generate much less efficient code (e.g. code that loads
>variables into registers one byte at a time).
How so? The actual mechanics of access to an object is transparent to a C
program. Only objects of type volatile sig_atomic_t can be accessed in an
indivisible operation, and even that might be done using some sort of locking
mechanism and multiple transfers.
If all mentions of alignment were removed from the standard (without removing
the implied restrictions), you would merely lose certain concepts that are
very useful in machine-specific coding.
But otherwise, I venture to guess, nothing would be affected.
A fault due to alignment can only happen in a C program that has somehow
created an invalid pointer. This could happen through the use of an
indeterminate pointer, or through a pointer that was converted from another
pointer type via a cast operator, or one that was derived from an integer via
a cast. But programs which do these sorts of things are not strictly
conforming, regardless of alignment. Alignment only explains the failures of
bad programs.
Take the cast operator for instance. The standard could simply say that
the result of casting one pointer to another might not yield a valid pointer,
except that casting a pointer to char to some other object and back recovers
that original pointer.
>Second, with regard to what alignment means: there is a binary
>predicate "<address> is suitably aligned for use as <type>" relating
>addresses and types. The standard specifies certain circumstances
>in which this predicate holds. Any attempt to use the storage at
>a given address to hold a value of a given type is undefined unless the
>standard specifies that the address is suitably aligned for that type.
>
>For example,
>
> int *p = (int *) malloc(sizeof(int));
> if (p) *p = 42;
>
>is well-defined, because the standard specifies that the result of
>malloc is such that when cast to any type, the result is suitably
>aligned for use as that type.
This could also be stipulated without appealing to the concept of alignment.
Simply declare that the pointer returned by malloc has the special property
that it may be converted to any object or incomplete pointer type, obtaining a
valid pointer.
>However,
>
> char buf[sizeof(int)];
> int *p = (int *) buf;
> if (p) *p = 42;
>
>is not well-defined, because there is no guarantee that the address
>is suitably aligned.
But it's also not also undefined because it aliases objects of incompatible
type?
I've never been able to make full sense of the access restrictions of section
6.3, so this might be a good time to bring them up (in another posting).
--
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Mark Wilden <Mark@mwilden.com>
Date: 1997/10/24 Raw View
Fergus Henderson wrote:
>
> the C++ draft states that expression in the argument
> of sizeof "is not evaluated" (5.3.3 [expr.sizeof], paragraph 1),
> and I'm sure the C standard says the same.
This is one example where an expression is never evaluated, can anyone
think of another? I can think of one...
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/24 Raw View
John Calcote wrote:
>
> However, I also understand your point. Compiler writers are allowed to look
> beyond internal expressions to the overall effect of a statement, such that
> "array[sizeof(array)]" doesn't generate a fault on the processor due to the
> fact that some code is being generated which dereferences an invalid
> address.
In fact they _have_ to look beyond. Even without an & in front
of it, what the processor does with array[sizeof(array)] depends
upon whether it's on the left side of an assignment operator or
not.
> In fact, compiler writers would have to actually go out of their way to
> implement a compiler which actually accesses a value at the "bad" address.
Exactly. What would it _do_ with that address? Read it or write
it?
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/24 Raw View
kaz@latte.cafe.net (Kaz) writes:
>If all mentions of alignment were removed from the standard (without removing
>the implied restrictions), you would merely lose certain concepts that are
>very useful in machine-specific coding.
Ah. The key phrase here is "without removing the implied restrictions".
In that case, what is being suggested is just a change in wording.
Now, would this change be a beneficial one?
Well, it would remove an implementation-oriented concept from
the language standard, which might be seen as a good thing.
On the other hand, using the implementation-oriented concept makes the
rationale for the rules immediately clear; removing it might make it
harder to understand the rationale.
I don't think it makes too much difference either way.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kaz@latte.cafe.net (Kaz)
Date: 1997/10/26 Raw View
In article <3450D848.108C@pratique.fr>,
Valentin Bonnard <bonnardv@pratique.fr> wrote:
>Fergus Henderson wrote:
>>
>> kaz@latte.cafe.net (Kaz) writes:
>>
>> >If all mentions of alignment were removed from the standard (without removing
>> >the implied restrictions), you would merely lose certain concepts that are
>> >very useful in machine-specific coding.
>>
>> Ah. The key phrase here is "without removing the implied restrictions".
>> In that case, what is being suggested is just a change in wording.
>
>So my real question is what are the implied restrictions ?
>
>So far, the only idea I have seen is malloc/operator new/new statement
>which return storage suitably aligned.
Alignment is also used to explain the validity of some pointer casts.
If you cast a pointer to one object (or incomplete) type to a different object
or incomplete type, a result is produced. However, that result might not be a
valid pointer (on grounds of alignment, but this is irrelevant to someone who
is writing a portable program).
When you dereference an invalid pointer, undefined behavior results.
A program that breaks these rules may fail because of an alignment exception.
However, this consideration is only relevant to someone who is writing
machine-specific code which takes advantage of otherwise dubious casts, and
who wants to ensure that this code executes without exceptions.
A program which breaks the rules might work on an 80386, but break on a HP-PA
RISC. The telltale signs are usually dubious pointer casts. A C program which
doesn't cast pointers, and does not dereference uninitialized or null pointers
cannot possible violate an alignment restriction.
Here are some things that you can do that *are* portable:
A strictly conforming C program may convert a pointer to an arbitrary object
or incomplete type to a pointer to a character type. If the original pointer
was valid, so is the character pointer. In this way, any object's bytes may be
examined individually using a pointer to char, and some pointer arithmetic.
An pointer to an object or incomplete type may also be converted to a pointer
to char, and then converted back. The result is the same as the original.
Similarly, a pointer to an object or incomplete type may be converted to a
pointer to void and back. The original value is recovered. In this case, no
cast operators are needed for the conversion (note: in C++ they _are_).
It's also possible to convert a pointer to a union object to a pointer to one
of its members, and vice versa; and to convert a pointer to a structure to a
pointer to the first member and vice versa.
Things like this are also valid:
{
int x[2];
char *p = (char *) x;
int *q = (int *) (p + sizeof(int));
/* q is now a valid pointer to int, referencing x[1] ... */
That's because the size of an object type includes allowance for alignment so
that adjacent members of an array will be properly aligned. Thus displacing
the pointer to char by an amount equal to the width of an int produces a
pointer that is still suitably aligned and may be converted back to a pointer
to int (provide I have not displaced the pointer out of bounds).
It would be awkward to separate the things that are allowed and work portably
from those that are not without appealing to alignment.
For example, why does the above fragment work, but the one below is not
portable?
{
int x[2];
char *p = (char *) x;
int *q = (int *) (p + 1);
It's because the pointer-to-char which points to the first byte of the x[]
array was displaced by a byte count other than the width of the int object.
The reason that a displacement that equals the width of an int is allowed, and
a displacement that doesn't equal the width is not allowed is because of
alignment.
Note that the subsequent use of *q no longer violates the aliasing
restrictions of section 6.3, because we can access the x[] array using *q
without breaking this rule. After all, *q has the same declared type as the
member elements of x[], and the implementation is required to heed the
possibility of aliasing between *q and x[].
The *only* problem here is the possible misalignment caused by displacing the
pointer by one byte.
Without the concept of addresses that are must be aligned to some multiples,
we could not easily explain why one snippet produces a valid pointer, and the
other does not.
--
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tanmoy Bhattacharya <tanmoy@qcd.lanl.gov>
Date: 1997/10/26 Raw View
Valentin Bonnard wrote:
<snip>
> > kaz@latte.cafe.net (Kaz) writes:
> >
> > >If all mentions of alignment were removed from the standard (without removing
> > >the implied restrictions), you would merely lose certain concepts that are
> > >very useful in machine-specific coding.
<snip>
> So my real question is what are the implied restrictions ?
>
> So far, the only idea I have seen is malloc/operator new/new statement
> which return storage suitably aligned.
I can only talk about the C language, not C++. As such, I do not deal
with issues like operator new/new statement etc.
In the C standard, there is mainly one place where the alignment
restrictions play a key role: it is to decide the result of casting from
one pointer type to another. Basically, if a pointer to a type T is cast
to a pointer of type U such that U has stronger alignment restrictions,
the result of the conversion need not be a valid pointer. Conversely, if
U has the same or ``less strict alignment`` requirement, then, in an
informal sense, the pointer is unchanged (formally, converting it back
will produce a pointer equal to the original one).
Thus, suppose there is an implementation that has longs aligned
`stricter than' ints: specifically that long has 8 byte alignment and
int has 2. Consider the declarations:
long x=0; int y=0; const long z=0;
Note that this does not mean that *(int *)&x is valid: that is subject
to other `no-aliasing' rules. But, (long *)(int*)&x == &x is guaranteed.
On the other hand (long *)&y itself may be an invalid pointer, and so
using it in any context (technically, even adding zero to it, or trying
to cast it, or assigning it to an object) leads to undefined behaviour.
Also, (int*)( (char*)&y + 1 ) need not give a valid pointer, but I think
it is reasonable to expect that (int*)( (char*)&x + 2 ) is a valid not
legally dereferenceable pointer, even if sizeof(int) is, say, 4.
Unfortunately, this does not quite follow: the standard is really vague
about results of pointer casts, e.g. it never quite specifies that
results of pointer conversions continue to point to the first byte that
comprises the pointee before the conversion: so, for example, nothing
implies that *(long*)&z == 0 (Who knows what `values stored' in 6.2.2.3
is talking about: expressions don't have values stored in them, but in
any case it does not apply here), even though the standard guarantees
there are no alignment problems, nor any problems with interpreting the
bit pattern in a const long object as a long object. It is also vague
about pointer arithmetic on a pointer created by pointer casts, so the
addition of the 2 above might be deemed invalid under some strict
readings of the standard. As there have not been, to my uncertain
knowledge, any DRs addressing these issues; it is best to assume the
minimum in this field. I, however, do pass `char *' strings to 'const
char *' parameters, and have never seen any unexpected behaviour due to
this.
Cheers
Tanmoy
--
tanmoy@qcd.lanl.gov(128.165.23.46) DECNET:
BETA::"tanmoy@lanl.gov"(1.218=1242)
Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity
Drive,NM87544
Others see
<gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. --
<http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003 voice: 1 (505) 665 4733 [ Home: 1 (505) 662
5596 ]
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1997/10/26 Raw View
Valentin Bonnard <bonnardv@pratique.fr> wrote in article
<344E71B6.446B9B3D@pratique.fr>...
> [Note : cross-posted to comp.std.c and comp.std.c++.]
> What would happen if we remove all sentences about alignement in both
> std ? (a clarification, I would guess)
Arguably there would be no excuse for sizeof struct{ T1 a; T2 b; } to be
different from sizeof(T1)+sizeof(T2).
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/26 Raw View
J. Kanze wrote:
>
> From a standards point of view, sizeof(*p) differs from &(*p) in that in
> the first, the (sub-)expression *p is not evaluated, whereas in the
> second, it is.
No, *p isn't evaluated, p is. What does it mean to "evaluate" *p
but to compute its value, which would mean reading the memory
location pointed to? I'll bet there isn't a single compiler out
there that reads the memory location pointed to by p when you
write &*p or &(*p).
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/26 Raw View
Bill Wade wrote:
>
> > You do have a right to do it. You get the contents of the first
> > word occupied by l. It's not the sort of thing you'd ever do
> > unless you knew the machine you were working on, since the
> > result would differ between a LE and BE machine.
>
> You don't have the right to do it (3.10 para 15). Even without alignment
> restrictions the assignment is undefined.
When they say "undefined", they mean that the standard doesn't
define the result. But it's obstinate legalism to assume that
the result is so intrinsically meaningless that the construct
should be prohibited, in those cases where you know the
underlying hardware structure. For that reason, I'd be pissed
off, justifiably I believe, if a compiler wouldn't let me cast a
long* to a short* and access through it. I do that sort of thing
all the time in intentionally non-portable embedded code.
> > What's certain,
> > though, is that since a short is no longer than a long, casting
> > a valid long pointer to a short pointer won't create a pointer
> > that violates the alignment requirements of short.
>
> As far as I can tell the standard allows
> sizeof(short) == 3;
> sizeof(long) == 5;
> union u { short s; long l; };
> sizeof(u) == 15;
> with alignment restrictions equal to size in each case. Such an
> implementation would mean that the code segment above violated the
> alignment restrictions of short.
Again, that's standing on one's head to find a technical reason
for rejecting something that is in practice perfectly
reasonable. There are no machines that enforce prime number
alignment requirements, and I daresay there never will be. And
to interpret the standard in such a manner that C++ couldn't be
properly implemented on such a hypothetical machine is no more
limiting than interpreting the standard so that C++ cannot be
implemented on a ternary machine, or a base ten machine, or an
analog machine. Such machines don't exist, except perhaps in the
back pages of Scientific American, so who cares?
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/26 Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> writes:
> Valentin Bonnard wrote:
> > > The term "suitably aligned" in the standard means just that:
> > > you can read or write any C variable type at that address
> > > without triggering a hardware problem.
> > But you just can't read a short where you wrote a long:
> >
> > long l = 4;
> > short* s = (short*) l;
> > int i = s; // can't do that !
>
> I assume you mean't *s in the last line.
Yes. At first I wanted to use a reference, then realised that
C programmers would have problems to understand that, so I
switched to a pointer, but I forgot to change the last line.
> > So what does it means 'without triggering a hardware problem'
> > when you don't have the right to do it ?
>
> You do have a right to do it. You get the contents of the first
> word occupied by l.
No you don't. It's undefined behaviour. There is no practical
garanty that you'll get something resonnable. For example, the
value of l might still be in a register, and i will contain
pure garbage.
The standard IMO doesn't even say that s points to l.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/26 Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> writes:
> Steve Clamage wrote:
> >
> > My mistake, as several people pointed out. The expression
> > array+array_size is allowed, because it just computes the address. The
> > expression I wrote implicitly dereferences that address, which is not
> > covered by the guarantees in the standard.
>
> But it's hard to imagine how one would write a compiler that
> would fail on &array[array_size], even if it's technically
> illegal.
On the contrary, this is easy; just add data to every pointer
about the bounds of the array it points to (non array type are
considered arrays of 1 element for this purpose). On each operation
on a pointer, check if it's still in the bounds. On dereferencing,
check that the pointer is non-null and not one-past-the-end.
One can represent a pointer as:
struct __pointer_type {
T* base;
size_t offset, size;
};
or
struct __pointer_type {
T *first, *current, *last;
};
or find annother representation.
Bound checking is common in other languages. For
traditionnal (?) reasons, it is rare in C/C++.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/22 Raw View
David R Tribble <david.tribble@central.beasys.com> writes:
|> | The question is, how is this [bad behavior] to be enforced? Presumably,
|> | constructors should throw an exception when attempting to bind reference
|> | members to null referents (maybe a 'bad_reference' exception?).
|>
|> The answer seems to be 'no, it is undefined behavior'. Which means that an
|> implementation can throw an exception if it wants to go to the trouble of
|> checking for bad reference bindings. But it doesn't have to. It can also
|> issue a compilation error if it can detect that the reference is being
|> bound to null. But it doesn't have to.
Right. FWIW: I have used one implementation which did do a run-time
check, and aborted the program if it failed. (Of course, it didn't
check if I was binding to memory I'd just freed, or something like
that.)
|> P.S.:
|> By the way, 'array+i' and '&array[i]' are exactly the same (as per the
|> original K&R). There is no dereferencing involved. To 'dereference' a
|> pointer is to 'access the memory pointed to by a pointer', no more and
|> no less.
No. The two expressions which are exactly the same, according to the
standard and K&R, are "*(array+i)" and "array[i]". In this case,
"exactly the same" means that both dereference. (By definition,
operator* dereferences.)
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/23 Raw View
[Note : cross-posted to comp.std.c and comp.std.c++.]
>Footnote 42 asserts that:
(ANSI C)
>an address inappropriately aligned for the type of the object pointed to
I have never been able to understand what alignement was... can anybody
help me, or it is just a void statement (and the notion of alignement
is just there to confuse people).
(Note: if you answer me, please make sure that your answer is justified
by the standard.)
What would happen if we remove all sentences about alignement in both
std ? (a clarification, I would guess)
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "John Hickin" <hickin@nortel.ca>
Date: 1997/10/23 Raw View
Tom Payne wrote:
>In the cases where the behavior is undefined (e.g., the case of &*p
>where p holds a value that is invalid for dereferencing), the behavior
>of &* is undefined, and therefore the compiler IS allowed to elide it.
Please forgive my slip. I should have said "if the compiler CHOOSES
to elide it".
>On the other hand, I don't see what such an allowance has to do with
>"the guarantee that comes with the use of references".
>
In essence, eliding &* represents an optimization that is unsafe. You
may manage to bind a reference to NULL and then pass the reference
on, but your program is already bad. I feel, therefore, that nobody
should have to test for reference arguments bound to NULL in the way
that they might test for a pointer argument equal to NULL. In this sense
we have a guarantee that references are 'nice'.
I'll digress to the example that is being discussed in other letters:
&x[n] being the same as x+n. This is a patently unsafe assumption.
It is guaranteed to work for only for certain values of n; the fact
that it is guaranteed for n being the number of elements is an artifact
of the standard which some implementations may have to work hard to
ensure. The fact that &* may be safely elided for certain values of n
does not mean that it may be safely elided at will. A compiler, could,
for example, treat &*& as & but generate code for &* that could be
removed by an optimizer; this extra code would have every right to
throw an exception.
Finally, I'd like to ask a question: can it be argued that the fact that
0-sized arrays are prohibited implies that eliding &* is unsafe? For
otherwise, element 0, being one past the end, would be allowed in the
expression &x[0].
--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hickin@nortel.ca
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/23 Raw View
In comp.std.c++ Tom Payne <thp@cs.ucr.edu> wrote:
: In comp.std.c++ David R Tribble <david.tribble@central.beasys.com> wrote:
: [...]
: : To 'dereference' a
: : pointer is to 'access the memory pointed to by a pointer', no more and
: : no less.
: : Computing the address of an object, whether the object exists or
: : not, is not a dereferencing operation but simply a pointer arithmetic
: : operation. That's why 'array+sizeof(array)' and '&array[sizeof(array)]'
: : are perfectly legal. You only get into problems if you try to access the
: : object at the address computed by these expressions, i.e., if you try
: : to dereference these pointer expressions.
: From 6.3.3.2 of the ANSI C Standard:
: The unary * operator denotes indirection. ... if [the operand]
: points to an object, the result is an lvalue designating the object.
: ... If an invalid value has been assigned to the pointer, the behavior
: of the unary * operator is undefined.^42
In past postings, I've seen it claimed that sizeof(*p) is well defined
even where p is a dangling pointer, "because finding the sizeof *p
does not require accessing p or *p." I don't, however, find any such
exception to 6.3.3.2 in the C Standard, and I presume that C++ is
similar.
Note that sizeof(*p) differs from &(*p) in that the latter, in
general, requires reading p, while (as long as p is not an array)
sizeof(*p) can be determined at compile time.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/23 Raw View
Jack Klein wrote:
>
> Valentin Bonnard <bonnardv@pratique.fr> wrote in article
> <344E71B6.446B9B3D@pratique.fr>...
> > [Note : cross-posted to comp.std.c and comp.std.c++.]
> >
> > >Footnote 42 asserts that: (ANSI C)
> > >an address inappropriately aligned for the type of the object pointed to
> >
> > I have never been able to understand what alignement was... can anybody
> > help me, or it is just a void statement (and the notion of alignement
> > is just there to confuse people).
> There are some processors which will not physically address
> certain size variables on an improper alignment.
True, but that's the implementor's problem.
> The term "suitably aligned" in the standard means just that:
> you can read or write any C variable type at that address
> without triggering a hardware problem.
[Here I assume that long has stronger alignement requirements
than short.]
But you just can't read a short where you wrote a long:
long l = 4;
short* s = (short*) l;
int i = s; // can't do that !
So what does it means 'without triggering a hardware problem'
when you don't have the right to do it ?
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Jack Klein" <jackklein@worldnet.att.net>
Date: 1997/10/23 Raw View
Valentin Bonnard <bonnardv@pratique.fr> wrote in article
<344E71B6.446B9B3D@pratique.fr>...
> [Note : cross-posted to comp.std.c and comp.std.c++.]
>
> >Footnote 42 asserts that: (ANSI C)
> >an address inappropriately aligned for the type of the object pointed to
>
> I have never been able to understand what alignement was... can anybody
> help me, or it is just a void statement (and the notion of alignement
> is just there to confuse people).
>
> (Note: if you answer me, please make sure that your answer is justified
> by the standard.)
>
> What would happen if we remove all sentences about alignement in both
> std ? (a clarification, I would guess)
There are some processors which will not physically address
certain size variables on an improper alignment. There are
processors like the Intel x86 series which will read/write a
value in a single bus cycle if it fits within the width of the
bus, and automatically generate two bus cycles if the item does
not. There are other processors which will not do this, but
generate hardware traps or faults if a memory reference is not
aligned correctly. I think the original Motorola 68000 was like
that.
The term "suitably aligned" in the standard means just that:
you can read or write any C variable type at that address
without triggering a hardware problem. On architectures where
there is no hardware problem, a quality of implementation issue
would be for the *alloc functions to use an alignment of the
processor's bus size, just for efficiency.
Jack
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/23 Raw View
"Jack Klein" <jackklein@worldnet.att.net> writes:
>Valentin Bonnard <bonnardv@pratique.fr> wrote in article
>> [Note : cross-posted to comp.std.c and comp.std.c++.]
>>
>> >Footnote 42 asserts that: (ANSI C)
>> >an address inappropriately aligned for the type of the object pointed to
>>
>> I have never been able to understand what alignement was... can anybody
>> help me, or it is just a void statement (and the notion of alignement
>> is just there to confuse people).
>>
>> (Note: if you answer me, please make sure that your answer is justified
>> by the standard.)
>>
>> What would happen if we remove all sentences about alignement in both
>> std ? (a clarification, I would guess)
>
>There are some processors which will not physically address
>certain size variables on an improper alignment.
We know that. But you didn't answer Valentin Bonnard's questions.
First, with regard to what would happen if you remove all sentences
about alignment: (1) existing compilers would become non-conforming
and (2) conforming compilers for the aforementioned processors would
often have to generate much less efficient code (e.g. code that loads
variables into registers one byte at a time).
Second, with regard to what alignment means: there is a binary
predicate "<address> is suitably aligned for use as <type>" relating
addresses and types. The standard specifies certain circumstances
in which this predicate holds. Any attempt to use the storage at
a given address to hold a value of a given type is undefined unless the
standard specifies that the address is suitably aligned for that type.
For example,
int *p = (int *) malloc(sizeof(int));
if (p) *p = 42;
is well-defined, because the standard specifies that the result of
malloc is such that when cast to any type, the result is suitably
aligned for use as that type.
However,
char buf[sizeof(int)];
int *p = (int *) buf;
if (p) *p = 42;
is not well-defined, because there is no guarantee that the address
is suitably aligned.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/10/23 Raw View
Valentin Bonnard wrote:
>
> [Note : cross-posted to comp.std.c and comp.std.c++.]
>
> >Footnote 42 asserts that:
> (ANSI C)
> >an address inappropriately aligned for the type of the object pointed to
>
> I have never been able to understand what alignement was... can anybody
> help me, or it is just a void statement (and the notion of alignement
> is just there to confuse people).
>
> (Note: if you answer me, please make sure that your answer is justified
> by the standard.)
Many machines can read 2 byte integers most easily if they start at
addressess which are multiples of 2; many machines can read 4 byte
integers or floats most easily if they start at addresses that are
multiples of 4; some machines will read any large object most easily if
it starts at an address that is a multiple of 16, etc. In general, using
a value stored at an off-alignment address involves doing a byte-by-byte
copy into a multi-byte register, or some similarly expensive technique.
The effect of those statements in the standard is to allow
implementations to produce code that works fast, at the cost of working
correctly only when items are aligned as needed. Such implementations
typically place variables with the correct alignment automatically; you
have to do tricky things using pointer casts to cause a problem.
>
> What would happen if we remove all sentences about alignement in both
> std ? (a clarification, I would guess)
Conforming compilers could never make any useful assumptions about the
alignment of a pointer. They would always need to include the slower
code needed to work with with arbitrary alignments. On some machines,
that code would necessarily be executed, even for properly aligned
pointers.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/24 Raw View
Valentin Bonnard wrote:
>
> > There are some processors which will not physically address
> > certain size variables on an improper alignment.
>
> True, but that's the implementor's problem.
Not really. The standard appears to be acknowledging that there
are some pointer values that can cause problems when
dereferenced, and attempting to define at least some of those
potential values. It's a programmer problem because the
programmer writes the code that potentially creates these bad
pointers. (Is the inability to dereference NULL an implementor's
problem?)
This doesn't mean that such dereferencing necessarily causes
problems. For instance, *(int*)0 "works" in most MS-DOS
programs, either accessing absolute memory location 0 or offset
0 within the data segment, depending upon the memory model.
> > The term "suitably aligned" in the standard means just that:
> > you can read or write any C variable type at that address
> > without triggering a hardware problem.
>
> [Here I assume that long has stronger alignement requirements
> than short.]
>
> But you just can't read a short where you wrote a long:
>
> long l = 4;
> short* s = (short*) l;
> int i = s; // can't do that !
I assume you mean't *s in the last line.
> So what does it means 'without triggering a hardware problem'
> when you don't have the right to do it ?
You do have a right to do it. You get the contents of the first
word occupied by l. It's not the sort of thing you'd ever do
unless you knew the machine you were working on, since the
result would differ between a LE and BE machine. What's certain,
though, is that since a short is no longer than a long, casting
a valid long pointer to a short pointer won't create a pointer
that violates the alignment requirements of short.
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/24 Raw View
Steve Clamage wrote:
>
> My mistake, as several people pointed out. The expression
> array+array_size is allowed, because it just computes the address. The
> expression I wrote implicitly dereferences that address, which is not
> covered by the guarantees in the standard.
But it's hard to imagine how one would write a compiler that
would fail on &array[array_size], even if it's technically
illegal.
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: john@mail.interlog.com (John R MacMillan)
Date: 1997/10/24 Raw View
|I have never been able to understand what alignement was... can anybody
|help me, or it is just a void statement (and the notion of alignement
|is just there to confuse people).
It's not just there to confuse people, it's there to allow compilers
to generate more efficient code. Many machines can access data
faster if it is suitably aligned.
|What would happen if we remove all sentences about alignement in both
|std ? (a clarification, I would guess)
The following snippet (and many like it) would presumably be legal
since 6.3.4 (Cast operators) would no longer say the resulting
pointer might be invalid:
char *buf;
long *lp;
buf = malloc(2 * sizeof(long));
if (buf != NULL) {
lp = (long *)(buf + 1);
*lp = 42;
}
This means mis-aligned pointers could exist. If mis-aligned pointers
can exist, then for a given pointer the compiler has to either assume
it may be, and generate slower code, or test, which would result in
slower code. And it would have to do this for every pointer for
which it could not prove, at compile time, was guaranteed to be
correctly aligned.
--
To reply by mail, please remove "mail." from my address -- but please
send e-mail or post, not both
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/24 Raw View
Tom Payne <thp@cs.ucr.edu> writes:
>In past postings, I've seen it claimed that sizeof(*p) is well defined
>even where p is a dangling pointer, "because finding the sizeof *p
>does not require accessing p or *p."
Right.
>I don't, however, find any such
>exception to 6.3.3.2 in the C Standard, and I presume that C++ is
>similar.
My copy of the C standard is not on hand right now,
but the C++ draft states that expression in the argument
of sizeof "is not evaluated" (5.3.3 [expr.sizeof], paragraph 1),
and I'm sure the C standard says the same.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/24 Raw View
Tom Payne <thp@cs.ucr.edu> writes:
|> In past postings, I've seen it claimed that sizeof(*p) is well defined
|> even where p is a dangling pointer, "because finding the sizeof *p
|> does not require accessing p or *p." I don't, however, find any such
|> exception to 6.3.3.2 in the C Standard, and I presume that C++ is
|> similar.
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/24 Raw View
Valentin Bonnard
>
> [Note : cross-posted to comp.std.c and comp.std.c++.]
>
> >Footnote 42 asserts that:
> (ANSI C)
> >an address inappropriately aligned for the type of the object pointed to
>
> I have never been able to understand what alignement was... can anybody
> help me, or it is just a void statement (and the notion of alignement
> is just there to confuse people).
Of course, you understand the meaning in terms of implementation, but ...
> (Note: if you answer me, please make sure that your answer is justified
> by the standard.)
you make the question much more difficult (and more interesting) when
you require that it be answered in terms of the semantics of the
language. I would say simply that a pointer is misaligned whenever
its value is incompatible with the requirements of its referrent type.
> What would happen if we remove all sentences about alignement in both
> std ? (a clarification, I would guess)
My view is that values of any particular type are represented by bit
patterns. We assign such a value to an object of that type by storing
the corresponding bit pattern into the segment of memory that
represents that object. But not every bit pattern that can be stored
in that object will necessarily represent a valid value of that type.
For instance, there are patterns that we can store in a float variable
that are not valid representations of real values per the IEEE
standard. Similarly, there are bit patterns that are simply not valid
values for pointers to ints (or "addresses of ints," if you prefer).
In some of the implementations I use, the two low-order bits of a bit
pattern must be zero in order for the pattern to represent a valid
int-pointer. If a int-pointer variable contains a pattern that
violates that constraint, then the pointer is misaligned. If a float
variable contain an invalid bit pattern we say that it is
"not-a-number." Perhaps there should be some generic term that
applies to all types.
Please pardon my rambling.
Regards,
Tom
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/21 Raw View
I wrote:
|> And speaking of rebinding references, you can set a reference variable to be
|> a null reference (i.e., bind the reference to no object). This little ditty
|> works on many compilers:
|> ...
|> int * p = NULL;
|> Foo baz(*p); // baz.iRef bound to *NULL <<<!>>>
|> ...
stephen.clamage_nospam@eng.sun.com (Steve Clamage) responded:
> It is not supposed to be possible to create a reference to null
> without invoking undefined behavior. I have yet to see a counter-
> example. Since this is comp.STD.c++, "works on many compilers" is not
> an interesting argument. Different compilers typically have different
> bugs and incompatible extensions.
> ...
> The last line of code has undefined semantics because it dereferences
> a null pointer. A particular implementation might compile and run the
> code without complaint, because "undefined behavior" includes the
> possibility of the code doing what you would like it to do. It also
> includes the possibility of the code failing to compile, or of
> aborting at run time.
> ...
> The code attempts to bind a reference to an expression with the value
> *0. The expression *0 has undefined semantics. We can also look at it
> another way: When defining a reference variable, it must be
> initialized to refer to an object. By definition, the null pointer
> does not point to any object, so no valid initialization of the
> reference can occur.
My original question, which was not directly answered by anyone, was:
| The question is, how is this [bad behavior] to be enforced? Presumably,
| constructors should throw an exception when attempting to bind reference
| members to null referents (maybe a 'bad_reference' exception?).
The answer seems to be 'no, it is undefined behavior'. Which means that an
implementation can throw an exception if it wants to go to the trouble of
checking for bad reference bindings. But it doesn't have to. It can also
issue a compilation error if it can detect that the reference is being
bound to null. But it doesn't have to.
P.S.:
By the way, 'array+i' and '&array[i]' are exactly the same (as per the
original K&R). There is no dereferencing involved. To 'dereference' a
pointer is to 'access the memory pointed to by a pointer', no more and
no less. Computing the address of an object, whether the object exists or
not, is not a dereferencing operation but simply a pointer arithmetic
operation. That's why 'array+sizeof(array)' and '&array[sizeof(array)]'
are perfectly legal. You only get into problems if you try to access the
object at the address computed by these expressions, i.e., if you try
to dereference these pointer expressions.
-- David R. Tribble, david.tribble@beasys.com --
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/21 Raw View
Steve Clamage wrote:
>
> But the expression &array[array_size] has always been allowed in C and
> C++. Just like a null pointer, the address (null or one past the end
> of the array) can be computed, assigned to a pointer, and compared to
> other addresses, but a pointer with that value cannot be dereferenced.
So while array[array_size] improperly dereferences a pointer
past the end of an array, &array[array_size] doesn't. This is a
case where & cancels out a dereference. Unless there's a
specific exception that makes that legal, then &*(T*)0 should be
a legal alias for (T*)0, even though *(T*)0 isn't, right?
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/21 Raw View
In comp.std.c++ David R Tribble <david.tribble@central.beasys.com> wrote:
[...]
: To 'dereference' a
: pointer is to 'access the memory pointed to by a pointer', no more and
: no less.
: Computing the address of an object, whether the object exists or
: not, is not a dereferencing operation but simply a pointer arithmetic
: operation. That's why 'array+sizeof(array)' and '&array[sizeof(array)]'
: are perfectly legal. You only get into problems if you try to access the
: object at the address computed by these expressions, i.e., if you try
: to dereference these pointer expressions.
Author: stephen.clamage_nospam@eng.sun.com (Steve Clamage)
Date: 1997/10/21 Raw View
On 21 Oct 97 11:28:49 GMT, "Paul D. DeRocco" <pderocco@ix.netcom.com>
wrote:
>Steve Clamage wrote:
>>
>> But the expression &array[array_size] has always been allowed in C and
>> C++. Just like a null pointer, the address (null or one past the end
>> of the array) can be computed, assigned to a pointer, and compared to
>> other addresses, but a pointer with that value cannot be dereferenced.
>
>So while array[array_size] improperly dereferences a pointer
>past the end of an array, &array[array_size] doesn't. ...
And on 21 Oct 97 11:53:53 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
>Do we have a special rule (in C or C++) which allows this particular
>case, or is it just a case of an undefined behavior that happens to work
>on (almost?) all implementations?
My mistake, as several people pointed out. The expression
array+array_size is allowed, because it just computes the address. The
expression I wrote implicitly dereferences that address, which is not
covered by the guarantees in the standard.
---
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/21 Raw View
stephen.clamage_nospam@eng.sun.com (Steve Clamage) writes:
|> On 17 Oct 97 16:45:30 GMT, Valentin Bonnard <bonnardv@pratique.fr>
|> wrote:
|>
|> >No you can't dereference 0, and at least that's not the intent in the
|> >DWP.
|> >But some people want to write &array[array_size] in order to get a
|> >past-the-end pointer. If that's allowed, then will dereferencing 0 be
|> >allowed too (where there is no lvalue to rvalue conversion) ?
|>
|> But the expression &array[array_size] has always been allowed in C and
|> C++. Just like a null pointer, the address (null or one past the end
|> of the array) can be computed, assigned to a pointer, and compared to
|> other addresses, but a pointer with that value cannot be dereferenced.
I think that the problem being referred to is that the expression
"array[ array_size ]" is the equivalent of "*(array + array_size)" (by
definition). So "&array[ array_size ]" is "&*(array + array_size)", and
we have the expression "*(array + array_size)", which is undefined
behavior.
Do we have a special rule (in C or C++) which allows this particular
case, or is it just a case of an undefined behavior that happens to work
on (almost?) all implementations?
--
James Kanze +33 (0)1 39 23 84 71 mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "John Hickin" <hickin@nortel.ca>
Date: 1997/10/21 Raw View
>We may be quibbling about the meaning of the word "dereference"
>here. I don't know if it's precisely defined in the draft
>standard. To me, however, it means accessing memory through a
>pointer. In this particular case, the * before the actual
>parameter is cancelled out ...
This may be true for some implementations but that behavior isn't
guaranteed by the standard. I used to wish that &* or *& behaved
that way officially but I have since come to see the other side of
coin.
One of the potential benefits of references is that they admit a
usage which allow us to code secure in the knowledge that an object
is there. That will be true unless we violate some language rule
by accident or design. If a compiler is allowed to elide &* I
feel that the guarantee that comes with the use of references would
be weakened.
BTW, although the standard doesn't mandate it, it is probably true
for any implementation that &*& and *&* may be replaced by & and *
and we may thus speak of & and * as being weak inverses of each other.
--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hickin@nortel.ca
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "John Calcote" <jcalcote@novell.com>
Date: 1997/10/21 Raw View
David R Tribble wrote in message
<2.2.32.19971020190540.00329b04@central.beasys.com>...
>P.S.:
>By the way, 'array+i' and '&array[i]' are exactly the same (as per the
>original K&R). There is no dereferencing involved. To 'dereference' a
>pointer is to 'access the memory pointed to by a pointer', no more and
>no less. Computing the address of an object, whether the object exists or
>not, is not a dereferencing operation but simply a pointer arithmetic
>operation. That's why 'array+sizeof(array)' and '&array[sizeof(array)]'
>are perfectly legal. You only get into problems if you try to access the
>object at the address computed by these expressions, i.e., if you try
>to dereference these pointer expressions.
David,
I think the author of this statement intended that &array[sizeof(array)] was
bad because compilers could (and do) take the expression to mean
&(array[sizeof(array)]), where the ampersand isn't applied until after the
array location is dereferenced. In other words, what's the difference
between:
i = array[sizeof(array)];
and
&array[sizeof(array)]
with respect to that portion, "array[sizeof(array)]", in the above
expressions?
However, I also understand your point. Compiler writers are allowed to look
beyond internal expressions to the overall effect of a statement, such that
"array[sizeof(array)]" doesn't generate a fault on the processor due to the
fact that some code is being generated which dereferences an invalid
address.
In fact, compiler writers would have to actually go out of their way to
implement a compiler which actually accesses a value at the "bad" address.
My Intel C++ compiler generates something like this:
; char array[50];
; char *ptr = &array[sizeof(array)];
lea eax, DWORD PTR _array$[ebp+50]
mov DWORD PTR _ptr$[ebp], eax
For non-Intel efficionados, the first line loads the effective address of
the location just past the end of the array (the 50th element) into the EAX
register - not the value at that address. The second line then places that
address into the "ptr" variable (declared on the stack, and referenced
relative to EBP). Never was the value at the address ever accessed. As I
stated above, compiler writers would have to take extra steps to actually
access the value during parsing of this sort of statement.
(Incidentally, array had to be defined explicitly as a CHAR array in order
to make sizeof(array) act like the sort of index I was interested in.)
Now, just to add another twist to the mixture: To handle just this
situation, the standard actually states that the memory location just past
the end of arrays must be valid, to handle machines which do a lot more
rigorous address checking than do Intel machines, or more specifically, to
handle boundary situations in which the address just beyond the end of an
array is incalculable - that is the declared array just happens to butt up
against the last addressable location in the system. How do you store the
address (0xFFFFFFFF + 1) on machines with 32-bit registers?
John
Novell
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/22 Raw View
In comp.std.c++ John Hickin <hickin@nortel.ca> wrote:
: One of the potential benefits of references is that they admit a
: usage which allow us to code secure in the knowledge that an object
: is there. That will be true unless we violate some language rule
: by accident or design. If a compiler is allowed to elide &* I
: feel that the guarantee that comes with the use of references would
: be weakened.
In the cases where the behavior is undefined (e.g., the case of &*p
where p holds a value that is invalid for dereferencing), the behavior
of &* is undefined, and therefore the compiler IS allowed to elide it.
On the other hand, I don't see what such an allowance has to do with
"the guarantee that comes with the use of references".
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/17 Raw View
And speaking of rebinding references, you can set a reference variable to be
a null reference (i.e., bind the reference to no object). This little ditty
works on many compilers:
#include <stdio.h>
class Foo
{
public:
Foo(int &o): iRef(o) { }
~Foo() { }
private:
int & iRef;
};
void myFunc()
{
int i;
Foo bar(i); // bar.iRef bound to i
printf("&bar.iRef=%p, &i=%p\n", &bar.iRef, &i);
int * p = NULL;
Foo baz(*p); // baz.iRef bound to *NULL <<<!>>>
printf("&baz.iRef=%p, &*p=%p\n", &baz.iRef, &*p);
}
Note that during the construction of 'baz', pointer 'p' does not actually
have to be dereferenced (and probably isn't) in order to pass an 'int&'
reference to the constructor.
--------------------. BEA Systems, Inc. ,-. +1-972-738-6125 Office
David R. Tribble \ ,------------------' \ +1-972-738-6111 Fax
http://www.beasys.com `-' Dallas, TX 75248 `-----------------------
david.tribble@noSPAM.beasys.com http://www.flash.net/~dtribble
Support the anti-Spam amendment, join at http://www.cauce.org/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/17 Raw View
In comp.std.c++ David R Tribble <david.tribble@central.beasys.com> wrote:
: And speaking of rebinding references, you can set a reference variable to be
: a null reference (i.e., bind the reference to no object). This little ditty
: works on many compilers:
: #include <stdio.h>
: class Foo
: {
: public:
: Foo(int &o): iRef(o) { }
: ~Foo() { }
: private:
: int & iRef;
: };
: void myFunc()
: {
: int i;
: Foo bar(i); // bar.iRef bound to i
: printf("&bar.iRef=%p, &i=%p\n", &bar.iRef, &i);
: int * p = NULL;
: Foo baz(*p); // baz.iRef bound to *NULL <<<!>>>
: printf("&baz.iRef=%p, &*p=%p\n", &baz.iRef, &*p);
: }
: Note that during the construction of 'baz', pointer 'p' does not actually
: have to be dereferenced (and probably isn't) in order to pass an 'int&'
: reference to the constructor.
I agree that it doesn't have to be dereferenced, but *p is still
an lvalue that lacks a valid referent and *should not* be suitable
as an argument to the constructor for Foo or to any other function
that takes an int& argument.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/17 Raw View
David R Tribble wrote:
>
> And speaking of rebinding references, you can set a reference variable to be
> a null reference (i.e., bind the reference to no object). This little ditty
> works on many compilers:
[Dereferencing 0, binding a reference to that, binding annother ref to
the ref and printing the address]
No you can't dereference 0, and at least that's not the intent in the
DWP.
But some people want to write &array[array_size] in order to get a
past-the-end pointer. If that's allowed, then will dereferencing 0 be
allowed too (where there is no lvalue to rvalue conversion) ?
> Note that during the construction of 'baz', pointer 'p' does not actually
> have to be dereferenced (and probably isn't) in order to pass an 'int&'
> reference to the constructor.
Writing *p is dereferencing p, but no lvalue to rvalue conversion
occurs.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/18 Raw View
David R Tribble <david.tribble@central.beasys.com> writes:
>And speaking of rebinding references, you can set a reference variable to be
>a null reference (i.e., bind the reference to no object). This little ditty
>works on many compilers:
It may well work on many compilers, but it has undefined behaviour.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/18 Raw View
[This is assuming that we use built-in & and *.]
David R Tribble <david.tribble@central.beasys.com> writes:
> I wrote:
> >> int * p = NULL;
> >> Foo baz(*p); // baz.iRef bound to *NULL <<<!>>>
> >>
> >> Note that during the construction of 'baz', pointer 'p' does not actually
> >> have to be dereferenced (and probably isn't) in order to pass an 'int&'
> >> reference to the constructor.
>
> Valentin Bonnard <bonnardv@pratique.fr> noted that:
> > Writing *p is dereferencing p, but no lvalue to rvalue conversion
> > occurs.
>
> Yes. But writing '&*p' is not really dereferencing 'p' - the compiler
> can collapse this to simply 'p'.
Well, '&*p' is a rvalue, but p is a lvalue, so '&*p' can't be read as p.
> Indeed, it has too. (Calling a function
> with a reference argument effectively prefixes the argument with an '&'.)
Calling a function with a non-const reference argument built a
reference using a lvalue. How this is done internally, and how
references are represented (if they occupy storage at all) is
the compiler job and is irrelevant here.
> Tom Payne <thp@cs.ucr.edu> commented:
> > I agree that it doesn't have to be dereferenced, but *p is still
> > an lvalue that lacks a valid referent and *should not* be suitable
> > as an argument to the constructor for Foo or to any other function
> > that takes an int& argument.
>
> I agree, '*NULL' should not be suitable as a reference argument to a
> constructor.
Right
> The question is, how is this to be enforced? Presumably,
> constructors should throw an exception when attempting to bind reference
> members to null referents (maybe a 'bad_reference' exception?).
> I don't have a copy of the CD2 to see if this is the case or not.
Dereferencing a pointer with a valid value not pointing to an
object (that is, a null or one past the end pointer) invoke
undefined behaviour.
Thus calling a ctor with a reference arguments built with a null
pointer has undefined behaviour, thus anything can happen, including
a core dump, the destruction of the universe or, as someone sugested,
a small electric shock through the keybord ('anything' includes
throwing an exception).
> If not, then perhaps we've found a deficiency in the draft.
No you haven't.
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/18 Raw View
I wrote:
>> int * p = NULL;
>> Foo baz(*p); // baz.iRef bound to *NULL <<<!>>>
>>
>> Note that during the construction of 'baz', pointer 'p' does not actually
>> have to be dereferenced (and probably isn't) in order to pass an 'int&'
>> reference to the constructor.
Valentin Bonnard <bonnardv@pratique.fr> noted that:
> Writing *p is dereferencing p, but no lvalue to rvalue conversion
> occurs.
Yes. But writing '&*p' is not really dereferencing 'p' - the compiler
can collapse this to simply 'p'. Indeed, it has too. (Calling a function
with a reference argument effectively prefixes the argument with an '&'.)
Tom Payne <thp@cs.ucr.edu> commented:
> I agree that it doesn't have to be dereferenced, but *p is still
> an lvalue that lacks a valid referent and *should not* be suitable
> as an argument to the constructor for Foo or to any other function
> that takes an int& argument.
I agree, '*NULL' should not be suitable as a reference argument to a
constructor. The question is, how is this to be enforced? Presumably,
constructors should throw an exception when attempting to bind reference
members to null referents (maybe a 'bad_reference' exception?).
I don't have a copy of the CD2 to see if this is the case or not. If not,
then perhaps we've found a deficiency in the draft.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/19 Raw View
Valentin Bonnard wrote:
>
> David R Tribble wrote:
> >
> > Note that during the construction of 'baz', pointer 'p' does not actually
> > have to be dereferenced (and probably isn't) in order to pass an 'int&'
> > reference to the constructor.
>
> Writing *p is dereferencing p, but no lvalue to rvalue conversion
> occurs.
We may be quibbling about the meaning of the word "dereference"
here. I don't know if it's precisely defined in the draft
standard. To me, however, it means accessing memory through a
pointer. In this particular case, the * before the actual
parameter is cancelled out by the & on the formal parameter.
While the standard may still define that as "dereferencing", it
isn't doing anything that has any good reason for being illegal,
in my view, since it isn't actually accessing the memory through
the pointer. One might intend never to access the value of the
reference member that is being initialized in this manner,
restricting oneself instead to taking its address. (Why one
would use a reference instead of a pointer in this case is
beyond me, but this seems a contrived example anyway.)
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/10/20 Raw View
stephen.clamage_nospam@eng.sun.com (Steve Clamage) writes:
>Valentin Bonnard <bonnardv@pratique.fr> wrote:
>
>>No you can't dereference 0, and at least that's not the intent in the
>>DWP.
>>But some people want to write &array[array_size] in order to get a
>>past-the-end pointer. If that's allowed, then will dereferencing 0 be
>>allowed too (where there is no lvalue to rvalue conversion) ?
>
>But the expression &array[array_size] has always been allowed in C and
>C++.
The expression `array + array_size' has always been allowed in C and C++.
The expression `&array[array_size]', however, is a bit more controversial.
A straight-forward reading of the C standard and the draft C++ standard
implies that this has undefined behaviour, because it dereferences
a past-the-end pointer.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: stephen.clamage_nospam@eng.sun.com (Steve Clamage)
Date: 1997/10/20 Raw View
On 17 Oct 97 16:45:30 GMT, Valentin Bonnard <bonnardv@pratique.fr>
wrote:
>No you can't dereference 0, and at least that's not the intent in the
>DWP.
>But some people want to write &array[array_size] in order to get a
>past-the-end pointer. If that's allowed, then will dereferencing 0 be
>allowed too (where there is no lvalue to rvalue conversion) ?
But the expression &array[array_size] has always been allowed in C and
C++. Just like a null pointer, the address (null or one past the end
of the array) can be computed, assigned to a pointer, and compared to
other addresses, but a pointer with that value cannot be dereferenced.
---
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: stephen.clamage_nospam@eng.sun.com (Steve Clamage)
Date: 1997/10/20 Raw View
On 19 Oct 97 09:07:02 GMT, "Paul D. DeRocco" <pderocco@ix.netcom.com>
wrote:
>We may be quibbling about the meaning of the word "dereference"
>here. I don't know if it's precisely defined in the draft
>standard. To me, however, it means accessing memory through a
>pointer. In this particular case, the * before the actual
>parameter is cancelled out by the & on the formal parameter.
I don't know how you reached that conclusion. Certainly the draft
standard does not speak of references cancelling out pointer
dereferencing. Don't confuse implementation details with the language
definition.
The code attempts to bind a reference to an expression with the value
*0. The expression *0 has undefined semantics. We can also look at it
another way: When defining a reference variable, it must be
initialized to refer to an object. By definition, the null pointer
does not point to any object, so no valid initialization of the
reference can occur.
---
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]