Topic: ANSI C++ comments


Author: steve@spokane.ia-us.com (Stephen Williams)
Date: 1995/05/25
Raw View
In article <EV.95May24105833@octave.chorus.fr> ev@octave.chorus.fr (Eric Valette) writes:


   I could not agree more. Dynamic libraries and loadable device drivers
   are also a problem I think.

They are addressed by the "translation unit initialization rule, and
some implementations properly handle it.

   eric>    to properly handle allocation failure. Implementing
   eric>    exceptions will probably makes assumption on the OS itself
   eric>    and thus this is clearly not acceptable for freestanding
   eric>    environment.

I still believe that an OS-free implementation of exceptions is
reasonable. It is a matter for the compiler vendor to handle such a
thing, and if necessary provide the run-time necessary to support the
environment he is selling into. (The unhandled exception is a
problem.)

As to your specific problem of allocation errors, there are a couple
solutions available within the language. First, you can overload new
and delete operators. This especially makes sense with embedded
systems where, for example objects are preallocated memory. An
overloaded new/delete can work with type-specific heaps.

You can also supply a new_handler that handles heap administration
(any MSVC++ programmers out there:-) without throwing an exception.

   Nothing is said about the way a class specific operator new can avoid
   the class constructor to be called if allocation fails.

If allocation fails, constructors are not called. Period.

   I would add what about run-time support needed for exception handling.

Part of the binary interface, especially the calling sequence. RTTI
will also need run-time support. I believe such can be sufficiently
compact to fit in embedded systems.

   BTW rereading the spec, I think the way it is formulated
    - impose a particular startup so that main return value
    is passed to exit routine
    - has it is said that it cannot be called explicitely,
    it cannot be used to volontary instanciate the globals...

A freestanding C++, obviously, would make that optional. I.e., the
above would be true *iff main were present.*

--

Stephen 2. Williams
 Work: steve@ia-us.com
 Home: steve@icarus.com

    Fight License Managers! Buy from
    vendors who use honor system!





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/05/28
Raw View
In article <JASON.95May22231303@phydeaux.cygnus.com>,
Jason Merrill <jason@cygnus.com> wrote:
>> 3.6.2 Initialization of non local objects
>> -----------------------------------------
>
>> I really think that linking a program with different
>> libraries that all have global instances will be a problem
>> if no way to define proper initalization is given to
>> programmer. (How can I use cout before the stream
>> package is initialized for instance).
>
>The standard streams are a special case, which an implementation must
>handle.  Most do this by use of ios::Init (27.4.3.1.6); you can use a
>similar hack in your own code.

 More to the point, cout isn't "initialised". It simply "is".
How this comes about is the vendors problem.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: ev@octave.chorus.fr (Eric Valette)
Date: 1995/05/23
Raw View
>>>>> "Jason" == Jason Merrill <jason@cygnus.com> writes:
In article <JASON.95May22231303@phydeaux.cygnus.com> jason@cygnus.com (Jason Merrill) writes:


>>>>> Eric Valette <ev@octave.chorus.fr> writes:

>> freestanding C does not impose to have a main function.
>> C++ has to impose a function that enables to construct
>> all global instances. The name "main" chosen for this
>> function is rather confusing.

Jason> Why not call your entry point 'main'?

Because I would prefer to have an entry point init_global_instances()
to perform th global instance initialization rather than main.

Imagine the follwowing code :

start ()
{
 initVirtualMemory();
 initInterruptions();
 initMicrokernel();
 main();
 microkernelStart();
 printf("should never get there\n");
}

1) it is bizarre!!!

2) What happens if main is defined inside into a C/ASM program? I bet
I will not construct any global instances.

Jason> If you are programming for an embedded target, you can write your own
Jason> version of exit, if indeed your product ever needs to shut itself down;
Jason> otherwise, there's no reason to care about destruction of static-duration
Jason> objects.

Except that if I link with a libc provided by the compiler vendor,
for the target processor I may have problem because of multiple exit
definition and that if I forget to link the C++ lib prior to the C lib
the object will never be destroyed for example.

>> 3.6.2 Initialization of non local objects
>> -----------------------------------------

>> I really think that linking a program with different
>> libraries that all have global instances will be a problem
>> if no way to define proper initalization is given to
>> programmer. (How can I use cout before the stream
>> package is initialized for instance).

Jason> The standard streams are a special case, which an implementation must
Jason> handle.  Most do this by use of ios::Init (27.4.3.1.6); you can use a
Jason> similar hack in your own code.

I just point out that the following program may or may not work
because of order of global instance initalization and that this
is a lack inside the language because the program is "well  formatted".
I just complain I have no control and this seems to me a missing feature.

--------------------file1.H-------------------------------------------
class  A {
 int * ptr;
public:
 A(int i) { ptr = new int; *ptr = i;}
 int getval() {return *ptr;}
};

extern A a;
---------------------file1.C-----------------------------------------
A a(1);
-------------------- file2.H-------------------------------------------
#include "file1.H"

class B {
 int i;
public:
 B() { i = a.getval();}
};
----------------------file2.C----------------------------------------------
B b;
----------------------file 3.C--------------------------------------------
// <=if b is constructed before A, the program crash before
// echoing the printf
main() { printf("hello world\n");}

---------------------------------------------------------------------------

};

>> The null pointer also is questionable because the C++ compiler
>> may use the specific null value without user knowlege as in the
>> following example for performing casts.

Jason> I think you misunderstand the concept of the null pointer value; there is
Jason> no requirement that it look like integer 0, though that is the most common
Jason> implementation.  In particular, (int)(void*)0 may or may not compare equal
Jason> to 0.

I wanted to explain that the compiler has to know a predefined value to
implement 4.10 third paragraph and I just wonder why there is no NIL keyword
as in many other language. I also need to be able to define this specific
value at compilation time or my code will be incorrect.

Thanks for your response, I just fear allthough thre is a normalization of
C++, the problem I was facing in the past are still there.



--
   __
  /  `                    Eric Valette
 /--   __  o _.           Chorus Systemes
(___, / (_(_(__          6 avenue Gustave Eiffel
    F-78182, St-Quentin-en-Yvelines-Cedex

Tel: +33 (1) 30 64 82 00 Fax: +33 (1) 30 57 00 66
E-mail: ev@chorus.fr










Author: steve@spokane.ia-us.com (Stephen Williams)
Date: 1995/05/23
Raw View
In article <EV.95May22193321@octave.chorus.fr> ev@octave.chorus.fr (Eric Valette) writes:


   I have a couple of comments that are mainly related to
   freestanding environment as defined in the processor
   compliant section.

   I know that some of the issues have been discussed but
   I would like to get the rationale for the final draft
   wording before submitting them via a more formal channel
   (e.g AFNOR).


I am extremely pleased to see that I am not the only one interested in
a freestanding C++ compiler. I find that I sometimes need such a beast
and believe C++ would be well suited for such a thing. My concerns are
different from Eric's, but I will comment on his.

   3.6 start and termination
   -------------------------

   freestanding C does not impose to have a main function.
   C++ has to impose a function that enables to construct
   all global instances. The name "main" chosen for this
   function is rather confusing. The same remarks is valid
   for the exit function and the global instances destruction.

I personally find the startup problem manageable. The C++ rule
requires simply that static initializers are called for translation
units (not programs) and must be called before any code in that
translation unit. I do not believe there is anything magical about the
TU that contains main(), so I believe that main() is not a theoretical
requirement of static initializers.

A device driver written in C++, for example, need not have a main. It
could have its initializers called before the first probe, or when it
is loaded, or whatever. I thus believe that a freestanding C++ need
not require main(), but still can (must) support initialization of
translation units.

   3.6.2 Initialization of non local objects
   -----------------------------------------

   I really think that linking a program with different
   libraries that all have global instances will be a problem
   if no way to define proper initalization is given to
   programmer. (How can I use cout before the stream
   package is initialized for instance).

This is a problem even with the full C++ rules. This has not proven to
be insurmountable and I do not believe a freestanding C++ requires any
special wording.

   3.7.3.1 Allocation functions
   ----------------------------

   The way the things are formulated impose to have exception
   to properly handle allocation failure. Implementing
   exceptions will probably makes assumption on the OS itself
   and thus this is clearly not acceptable for freestanding
   environment.

I believe not. Exceptions impose requirements of the run-time that can
be implemented independent of any OS, or void of any OS. The details
may be CPU specific, but that is OK as it's the compiler's job to
handle such things.

The real problem is not exceptions, but unhandled exceptions.

   The null pointer also is questionable because the C++ compiler
   may use the specific null value without user knowlege as in the
   following example for performing casts.

 [...]

   We do want to support embedded application  were 0 is a valid
   address (e.g on processor with signed memory). With C there is
   no such problem has the null pointer is never interpreted by
   the compiler itself.

I do not believe the bit pattern is specified for '0'. The value of
(void*)0 may be very different from int(0). I think as long as some
value can be chosen, any value will do. The compiler can manage such
things. Is that not why 0 is given special meaning?

   12.25 Free store
   ----------------

   It is unspecified under what circumstances the contructor will be automatically
   be called. Again if the only way to prevent the constructor to be called is
   throwing exception this is not acceptable. If the following code is legal
   this is fine : [...]

Je ne comprend pas?


What is needed to make a freestanding C++ is a list of things that
rightly belong in a full standard (i.e. iostreams.h) but are not
required for a freestanding compiler. Free store does need to be
looked at. In fact, the whole std:: namespace needs to be looked
at. What about standard templates such as basic_string? Should they be
a required part of a freestanding compiler, or just allowed?
What about unexpected exceptions?

--

Stephen 2. Williams
 Work: steve@ia-us.com
 Home: steve@icarus.com

    Fight License Managers! Buy from
    vendors who use honor system!





Author: jason@cygnus.com (Jason Merrill)
Date: 1995/05/23
Raw View
>>>>> Eric Valette <ev@octave.chorus.fr> writes:

> 3.6 start and termination
> -------------------------

> freestanding C does not impose to have a main function.
> C++ has to impose a function that enables to construct
> all global instances. The name "main" chosen for this
> function is rather confusing.

Why not call your entry point 'main'?

> The same remarks is valid for the exit function and the global instances
> destruction.

Why not call the function to end execution cleanly 'exit'?

If you are programming for an embedded target, you can write your own
version of exit, if indeed your product ever needs to shut itself down;
otherwise, there's no reason to care about destruction of static-duration
objects.

> 3.6.2 Initialization of non local objects
> -----------------------------------------

> I really think that linking a program with different
> libraries that all have global instances will be a problem
> if no way to define proper initalization is given to
> programmer. (How can I use cout before the stream
> package is initialized for instance).

The standard streams are a special case, which an implementation must
handle.  Most do this by use of ios::Init (27.4.3.1.6); you can use a
similar hack in your own code.

> On freestanding program, the initialization is even worse since you must
> initialize a great amount of things before calling constructors (thus
> main cannot be the entry point....).

So write your own startup code (i.e. crt0) which does domain-specific
initialization before calling main.

> 3.7.3.1 Allocation functions
> ----------------------------

> The way the things are formulated impose to have exception
> to properly handle allocation failure. Implementing
> exceptions will probably makes assumption on the OS itself
> and thus this is clearly not acceptable for freestanding
> environment.

> NB : if the following construct is allowed, this is sufficient
> for our needs :

> class A {
> public:
>  A(int);
> };

> f()
> {
>  A *ptr = ::operator new (sizeof(A));
>  if (ptr != (A*) 0) ptr->A(1);
> }

> but is is not clear to me that this construct is legal.

It isn't.  However, this should do what you want:

 if (ptr != (A*) 0) new (ptr) A(1);

> The null pointer also is questionable because the C++ compiler
> may use the specific null value without user knowlege as in the
> following example for performing casts.

I think you misunderstand the concept of the null pointer value; there is
no requirement that it look like integer 0, though that is the most common
implementation.  In particular, (int)(void*)0 may or may not compare equal
to 0.

Jason





Author: ev@octave.chorus.fr (Eric Valette)
Date: 1995/05/24
Raw View
>>>>> "Stephen" == Stephen Williams <steve@spokane.ia-us.com> writes:
In article <STEVE.95May23121456@spokane.ia-us.com> steve@spokane.ia-us.com (Stephen Williams) writes:


Stephen> I am extremely pleased to see that I am not the only one interested in
Stephen> a freestanding C++ compiler. I find that I sometimes need such a beast
Stephen> and believe C++ would be well suited for such a thing. My concerns are
Stephen> different from Eric's, but I will comment on his.

I see so many people in the embedded marked using C today an wanting to go
to C++ that I think this should really be addressed. There are so much drivers,
microcontrollers programmed in C today that the standart will really miss
something in not applicable for freestanding environment.

Stephen> A device driver written in C++, for example, need not have a main. It
Stephen> could have its initializers called before the first probe, or when it
Stephen> is loaded, or whatever. I thus believe that a freestanding C++ need
Stephen> not require main(), but still can (must) support initialization of
Stephen> translation units.

I could not agree more. Dynamic libraries and loadable device drivers
are also a problem I think.

Stephen> This is a problem even with the full C++ rules. This has not proven to
Stephen> be insurmountable and I do not believe a freestanding C++ requires any
Stephen> special wording.

I agree. I just say that what the possible use of the standart could be to
close some original C++ flaw :-).

eric>    to properly handle allocation failure. Implementing
eric>    exceptions will probably makes assumption on the OS itself
eric>    and thus this is clearly not acceptable for freestanding
eric>    environment.

Stephen> I believe not. Exceptions impose requirements of the run-time that can
Stephen> be implemented independent of any OS, or void of any OS. The details
Stephen> may be CPU specific, but that is OK as it's the compiler's job to
Stephen> handle such things.

Do you really think to setjump and longjump like function are really
OS independent? Since I haven't seen the run-time specification for exception
handling, I do not even know what I will have to support if I need exceptions.


Stephen>    12.25 Free store
Stephen>    ----------------

Stephen>    It is unspecified under what circumstances the contructor will be automatically
Stephen>    be called. Again if the only way to prevent the constructor to be called is
Stephen>    throwing exception this is not acceptable. If the following code is legal
Stephen>    this is fine : [...]

Stephen> Je ne comprend pas?

Nothing is said about the way a class specific operator new can avoid
the class constructor to be called if allocation fails. For the global
operator new, in the std library there is a

 void* operator new (size_t, const &nothrow) throw ();

that will do what is needed (e.g not call the class constructor).
For an OS, for performances reasons, dynamic data structure allocation
are usually taken from dedicated pools that can have finite size for
non virtual memory system. I need to be able to recover when the pool
is empty. Since I do not know what run-time support is needed to perform
exception catching, I would like to handle it without throwing anything.

Stephen> What is needed to make a freestanding C++ is a list of things that
Stephen> rightly belong in a full standard (i.e. iostreams.h) but are not
Stephen> required for a freestanding compiler. Free store does need to be
Stephen> looked at. In fact, the whole std:: namespace needs to be looked
Stephen> at. What about standard templates such as basic_string? Should they be
Stephen> a required part of a freestanding compiler, or just allowed?
Stephen> What about unexpected exceptions?

I would add what about run-time support needed for exception handling.

Thanks for your concern and I guess you gave me a much better reason
for requesting something else than main to initialize global instances.

BTW rereading the spec, I think the way it is formulated
 - impose a particular startup so that main return value
 is passed to exit routine
 - has it is said that it cannot be called explicitely,
 it cannot be used to volontary instanciate the globals...

--
   __
  /  `                    Eric Valette
 /--   __  o _.           Chorus Systemes
(___, / (_(_(__          6 avenue Gustave Eiffel
    F-78182, St-Quentin-en-Yvelines-Cedex

Tel: +33 (1) 30 64 82 00 Fax: +33 (1) 30 57 00 66
E-mail: ev@chorus.fr










Author: steve@spokane.ia-us.com (Stephen Williams)
Date: 1995/05/24
Raw View
   >>>>> Eric Valette <ev@octave.chorus.fr> writes:

   >> freestanding C does not impose to have a main function.
   >> C++ has to impose a function that enables to construct
   >> all global instances. The name "main" chosen for this
   >> function is rather confusing.

   Jason> Why not call your entry point 'main'?

   Because I would prefer to have an entry point init_global_instances()
   to perform th global instance initialization rather than main.

You can supply your own crt that calls anything you want, other then
main. In theory, the compiler implemented using a hypothetical
freestanding C++ would handle translation units consistently, and
would take care of this. In practice, you will have to provide a
little of this yourself.

   Jason> If you are programming for an embedded target, you can write your own
   Jason> version of exit, if indeed your product ever needs to shut itself down;
   Jason> otherwise, there's no reason to care about destruction of static-duration
   Jason> objects.

   Except that if I link with a libc provided by the compiler vendor,
   for the target processor I may have problem because of multiple exit
   definition and that if I forget to link the C++ lib prior to the C lib
   the object will never be destroyed for example.

Freestanding C does not include the C library. So you are suggesting
writing C++ for a freestanding C++, and C for a hosted C compiler? I
think you are on your own here. I believe a freestanding C++ would be
based on freestanding C, and the introduction of libraries would be at
your own risk.

   Jason> The standard streams are a special case, which an implementation must
   Jason> handle.  Most do this by use of ios::Init (27.4.3.1.6); you can use a
   Jason> similar hack in your own code.

   I just point out that the following program may or may not work
   because of order of global instance initalization and that this
   is a lack inside the language because the program is "well  formatted".
   I just complain I have no control and this seems to me a missing feature.

Initialization order can be a little funky, but you are not completely
without control. Within a translation unit, objects are initialized in
the order they are defined. It is the order that the translation units
are initialized that is not specified by the standard. A freestanding
C++ should not be any different in this regard.


   Jason> I think you misunderstand the concept of the null pointer value; there is
   Jason> no requirement that it look like integer 0, though that is the most common
   Jason> implementation.  In particular, (int)(void*)0 may or may not compare equal
   Jason> to 0.

   I wanted to explain that the compiler has to know a predefined value to
   implement 4.10 third paragraph and I just wonder why there is no NIL keyword
   as in many other language. I also need to be able to define this specific
   value at compilation time or my code will be incorrect.

'0' is overloaded to mean 'nil' in certain contexts. And yes, the
compiler needs to know what that number is in order to generate
assembly code. (I can imagine a compiler that generates a symbolic
constant for the assembler, but some handy optimizations may be lost.)

--

Stephen 2. Williams
 Work: steve@ia-us.com
 Home: steve@icarus.com

    Fight License Managers! Buy from
    vendors who use honor system!





Author: ev@octave.chorus.fr (Eric Valette)
Date: 1995/05/22
Raw View
Dear sirs,

I have a couple of comments that are mainly related to
freestanding environment as defined in the processor
compliant section.

I know that some of the issues have been discussed but
I would like to get the rationale for the final draft
wording before submitting them via a more formal channel
(e.g AFNOR).


---------------------comments---------------------------

3.6 start and termination
-------------------------

freestanding C does not impose to have a main function.
C++ has to impose a function that enables to construct
all global instances. The name "main" chosen for this
function is rather confusing. The same remarks is valid
for the exit function and the global instances destruction.

Getting the calling context in argc, argv is another
issue and maybe main has also to exist anyway.

3.6.2 Initialization of non local objects
-----------------------------------------

I really think that linking a program with different
libraries that all have global instances will be a problem
if no way to define proper initalization is given to
programmer. (How can I use cout before the stream
package is initialized for instance). On freestanding
program, the initialization is even worse since you must
initialize a great amount of things before calling
constructors (thus main cannot be the entry point....).

3.7.3.1 Allocation functions
----------------------------

The way the things are formulated impose to have exception
to properly handle allocation failure. Implementing
exceptions will probably makes assumption on the OS itself
and thus this is clearly not acceptable for freestanding
environment.

NB : if the following construct is allowed, this is sufficient
for our needs :

class A {
public:
 A(int);
};

f()
{
 A *ptr = ::operator new (sizeof(A));
 if (ptr != (A*) 0) ptr->A(1);
}

but is is not clear to me that this construct is legal.


The null pointer also is questionable because the C++ compiler
may use the specific null value without user knowlege as in the
following example for performing casts.

class A {} ;
class B {};

class C : public A, public B {}

const void* nullp = (void*) 0;

C* ptrC = (C*) nullp;

void g(B* ptrB)
{
 if (ptrB != nullp) {}
}

main()
{
 B* ptrB = ptrC; // <====what is the value of ptrB? 0 or something else
 g(ptrC);
 g(ptrB);
}

We do want to support embedded application  were 0 is a valid
address (e.g on processor with signed memory). With C there is
no such problem has the null pointer is never interpreted by
the compiler itself.


12.25 Free store
----------------

It is unspecified under what circumstances the contructor will be automatically
be called. Again if the only way to prevent the constructor to be called is
throwing exception this is not acceptable. If the following code is legal
this is fine :

const void* nullp = (void*) -1;

class A {

public :
 void * operator new(unsigned int size);
 A(int);
}

f()
{
     A *ptr = A::operator new(sizeof(A));
 if (ptr != (A*) nullp) ptr->A();
 ...
}
--
   __
  /  `                    Eric Valette
 /--   __  o _.           Chorus Systemes
(___, / (_(_(__          6 avenue Gustave Eiffel
    F-78182, St-Quentin-en-Yvelines-Cedex

Tel: +33 (1) 30 64 82 00 Fax: +33 (1) 30 57 00 66
E-mail: ev@chorus.fr