C++ and Portability
© , , , , The TenDRA Project.
© DERA.
First published .
Revision History
kate | Moved out the DRA producers as a standalone tool. | |
kate | Split off from tcpplus. | |
DERA | tcpplus 1.8.2; TenDRA 4.1.2 release. |
1. Common porting problems
Experience in porting pre-ISO C++ programs has shown that the following new ISO C++ features tend to cause the most problems:
-
Implicit
int
has been banned. -
String literals are now
const
, although in simple assignments theconst
is implicitly removed. -
The scope of a variable declared in a for-init-statement is the
for
statement itself. -
Variables have linkage and so should be declared
extern "C"
if appropriate. -
The standard C library is now declared in the
std
namespace. -
The template compilation model has been clarified. The notation for explicit instantiation and specialisation has changed.
-
Templates are analysed at their point of definition as well as their point of instantiation.
-
New keywords have been introduced.
Note that many of these features have controlling #pragma
directives, so that it is possible to switch to using the pre-ISO features.
2. Porting libio
Perhaps the library component which is most likely to be required is <iostream>
. A readily available freeware implementation of a pre-ISO (i.e. non-template) <iostream>
package is given by the libio
component of libg++
. This section describes some of the problems encountered in porting this package (version 2.7.1).
The tcc compiler flags used in porting libio
were:
tcc -Yposix -Yc++ -sC:cc
indicating that the POSIX API is to be used and that the .cc
suffix is used to identify C++ source files.
In iostream.h
, cin
, cout
, cerr
and clog
should be declared with C linkage, otherwise the C++ producer includes the type in the mangled name and the fake iostream
hacks in stdstream.cc
don't work. The definition of EOF
in this header can cause problems if both iostream.h
and stdio.h
are included. In this case stdio.h
should be included first.
In stdstream.cc
, the correct definitions for the fake iostream
structures are as follows:
struct _fake_istream::myfields { _ios_fields *vb ; // pointer to virtual base class ios _IO_ssize_t _gcount ; // istream fields void *vptr ; // pointer to virtual function table } ; struct _fake_ostream::myfields { _ios_fields *vb ; // pointer to virtual base class ios void *vptr ; // pointer to virtual function table } ;
The fake definition macros are then defined as follows:
#define OSTREAM_DEF( NAME, SBUF, TIE, EXTRA_FLAGS )\ extern "C" _fake_ostream NAME = { { &NAME.base, 0 }, .... } ; #define ISTREAM_DEF( NAME, SBUF, TIE, EXTRA_FLAGS )\ extern "C" _fake_istream NAME = { { &NAME.base, 0, 0 }, .... } ;
Note that these are declared with C linkage as above.
In stdstrbufs.cc
, the correct definitions for the virtual function table names are as follows:
#define filebuf_vtable __vt__7filebuf #define stdiobuf_vtable __vt__8stdiobuf
Note that the _G_VTABLE_LABEL_PREFIX
macro is incorrectly defined by the configuration process (it should be __vt__
), but the ##
directives in which it is used don't work on an ISO compliant preprocessor anyway (token concatenation takes place after replacement of macro parameters, but before further macro expansion). The dummy virtual function tables should also be declared with C linkage to suppress name mangling.
In addition, the initialisation of the standard streams relies on the file pointers stdout
etc. being constant expressions, which in general they are not. The directive:
#pragma TenDRA++ rvalue token as const allow
will cause the C++ producer to assume that all tokenised rvalue expressions are constant.
In streambuf.cc
, if errno
is to be explicitly declared it should have C linkage or be declared in the std
namespace.
In iomanip.cc
, the explicit template instantiations should be prefixed by template
. The corresponding template declarations in iomanip.h
should be declared using export
(note that the __GNUG__
version uses extern
, which may yet win out over export
).