Portable code

Hi, (the wintel-lamer again)

I’m already trying hard to learn all basics of portable code design.
I left all the Windows specific stuff behind and I am currently trying
to convert my current code base to a portable state. But I need some
help:

Are there any good pages on portable C/C++ code (including library and
system specific compilation dependencies)? Maybe even a tutorial by any
of the SDL pro’s?

Boris

Well, I would recommend using a cross platform library, and stay within
ansi c only… ofcourse even with ansi c, it doesn’t always do the same
thing on different platforms… you will also want to look into and learn
how to use the #if preproccesor directives… then on the differnet stuff
that doesn’t work you can do like #if WIN32 or #if LINUX or something like
that…

i have seen some c bibles that have the function name and what os they are
supported under. that would be cool too…On Sat, 19 Feb 2000, Boris Bauer wrote:

Hi, (the wintel-lamer again)

I’m already trying hard to learn all basics of portable code design.
I left all the Windows specific stuff behind and I am currently trying
to convert my current code base to a portable state. But I need some
help:

Are there any good pages on portable C/C++ code (including library and
system specific compilation dependencies)? Maybe even a tutorial by any
of the SDL pro’s?

Boris

Hi, (the wintel-lamer again)

I’m already trying hard to learn all basics of portable code design.
I left all the Windows specific stuff behind and I am currently trying
to convert my current code base to a portable state. But I need some
help:

Are there any good pages on portable C/C++ code (including library and
system specific compilation dependencies)? Maybe even a tutorial by any
of the SDL pro’s?

Most of the function documentation on MSDN has portability notes for the
functions. In general, if it’s portable across ANSI C standard, then it
will be portable to most current systems.

Anybody else?

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

— Sam Lantinga wrote:

Hi, (the wintel-lamer again)

I’m already trying hard to learn all basics of portable code
design.
I left all the Windows specific stuff behind and I am currently
trying
to convert my current code base to a portable state. But I need
some
help:

Are there any good pages on portable C/C++ code (including library
and
system specific compilation dependencies)? Maybe even a tutorial by
any
of the SDL pro’s?

Most of the function documentation on MSDN has portability notes for
the
functions. In general, if it’s portable across ANSI C standard, then
it
will be portable to most current systems.

Anybody else?

Depending on what you want in ‘portable’ templates are usually bad,
multiple inheritance is bad, you also need to keep track of
endian-ness. Just because it’s a ANSI C standard doesn’t mean it’s
implemented on the target platform correctly (though I wish it were, or
at least consistant).=====
Jason Platt.

“In theory: theory and practice are the same.
In practice: they arn’t.”


Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.

Here’s a quick list of some of them, stolen from one of the header
files from the crystal space project.

#ifdef OS_WIN32
#if defined (COMP_WCC) && defined (OS_DOS)
#if defined (COMP_GCC) && defined (OS_DOS)
#if defined (OS_MACOS)
#if defined (OS_UNIX) && !defined(OS_BE)
#if defined (OS_AMIGAOS)
#if defined (OS_OS2)
#if defined (OS_BE)
#if defined (OS_NEXT)

— Ryan wrote:> Well, I would recommend using a cross platform library, and stay

within
ansi c only… ofcourse even with ansi c, it doesn’t always do the
same
thing on different platforms… you will also want to look into and
learn
how to use the #if preproccesor directives… then on the differnet
stuff
that doesn’t work you can do like #if WIN32 or #if LINUX or something
like
that…

i have seen some c bibles that have the function name and what os
they are
supported under. that would be cool too…

On Sat, 19 Feb 2000, Boris Bauer wrote:

Hi, (the wintel-lamer again)

I’m already trying hard to learn all basics of portable code
design.
I left all the Windows specific stuff behind and I am currently
trying
to convert my current code base to a portable state. But I need
some
help:

Are there any good pages on portable C/C++ code (including library
and
system specific compilation dependencies)? Maybe even a tutorial by
any
of the SDL pro’s?

Boris

=====
Jason Platt.

“In theory: theory and practice are the same.
In practice: they arn’t.”


Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.

Boris Bauer wrote:

Are there any good pages on portable C/C++ code (including library and
system specific compilation dependencies)? Maybe even a tutorial by any
of the SDL pro’s?

I’ve been doing a little bit of portability stuff (unofficially) here at
Creature Labs.
As I go, I’m trying to put together a list of portability guidelines.

We’re using C++, primary platform is win32, Visual C/C++. I’ve been
doing stuff with the latest gcc versions under Linux. MacOS, OSX,
Playstation 2, Codewarrior are also platforms/tools of interest, but I
haven’t done any serious research on them.

Here is what I’ve come up with so far - I’d love it if people had
items to add :slight_smile:

IFDEF USAGE============

Generally, it’s a good idea to switch on feature ifdefs rather than
platform ifdefs. Some examples:

  • use BIGENDIAN where appropriate instead of MACOS.
  • instead of #ifdef LINUX, try using #ifdef POSIX - most calls you do
    under linux are general enough to apply to other unix-based systems (and
    most probably OSX)

I generally use a project or library-specific prefix for these #defines.


Don’t mix up compiler defines and platform defines.
eg:

#ifdef _MSC_VER
#pragma turn-off-pesky-warning-messages
#endif // _MSC_VER
Note that the compiler symbol (_MSC_VER) is used, NOT the platform
define (_WIN32).

COMPILER DIFFERENCES

Visual C/C++ will let you get away with a lot of stuff it probably
shouldn’t.
Visual C does have a ‘strict’ option buried away somewhere, but it is
left off by default to allow MFC code to compile. Hmm.

In general, using multiple compilers is a good thing for ensuring you
write standard code.

Some specifics:


Recent versions of gcc seem ok with regards to templates and exceptions
(it’s traditional weak points). It does produce big debug executables
though - one project I have produces a 50 meg exe under gcc vs about 6
meg with VC. I suspect this is due to template usage.


Invalid comparisons eg:
unsigned int foo = getvalue();
if( foo == -1 ) …

gcc will point out that the ‘if’ statement condition is invalid
(because foo is unsigned) but visual C seems to let it through OK.


ANSI requires that you provide an explict cast when assigning to
a pointer type from a void*. VC seems a more casual about this than gcc.


gcc is more strict on casting.

eg: int32 is not automatically cast to int.

typedef unsigned long int int32;
int32 x=5,y=10;
Vector2D v(x,y);

If Vector2D provides Vector2D(int,int) or Vector2D(float,float), gcc
won’t automatically assume you mean the integer one.

Q: Is this ansi or just gcc?


Later versions of g++ (I.E. X-mas '99 onward are very strict with regard
to const references for some reason - this is a pervasive change)


gcc (2.95.2) bugette:

bool wibble()
{
printf(“Wibble!\n”);
}

gcc doesn’t seem to mind the lack of return value.
(Maybe -Wall option would help?)


gcc (at least without -Wall) doesn’t seem to pick up when you use an
uninitialised var.

eg:

int i;
switch(foo)
{
case 0: i=0; break;
case 1: i += 10; break // !!!
case 2: i = 42; break;
}

compiles without warning…


std::string being passed in to va_start() for printf-style formatting.
eg:
void foo( std::string fmt, … );

gcc warns you that fmt is a string and that you can’t pass strings as
varargs. VC lets it through.
The code would probably be OK if you use fmt.c_str() in the
vsprintf() line.


Visual C has some very non-ansi behaviour when it comes to variables
declared in for loops, eg:

for( int i=0; i<10; ++i ) {…}

Ansi states that i is only in scope for the duration of the loop, but VC
leaves it in scope.

C++ LIBRARY STUFF

Quite often a dodgy bit of code will work fine under one std C++
library/STL implementation, but will fall over badly on another. Those
libraries are generally pretty specific about what you can or can’t
assume about their implementation.

For example, keeping raw pointers into std::string objects.

Dodgy because the contents can be reallocated and copied about by the
implementation.
In general, any pointers obtained using data() or c_str() should be
considered invalid after any other operations on the string object.
(what does ansi say?)


The C++ library standard has only recently been finalised. Many (all?)
compilers come with libs which don’t adhere exactly to the standard for
one reason or another.
Eg:

std::stringstream isn’t currently available under the bog-standard gcc
distribution.

The VC std c++ headers have some problems with max and min due to
clashes in the windows header files.

GENERAL

Don’t use lightweight wrapper classes to wrap platform specific APIs -
instead try to abstract the
interface out to platform independence.


Filename case sensitivity can be a fiddly problem. win32 doesn’t care
about case (although I think you can set up NTFS to be case sensitive),
but most unix-based systems do. Using all lower-case filenames is
probably a reasonable solution.

Also, path separation characters differ - win32 uses ‘’ and ‘:’, others
use ‘/’, mac uses ‘:’ (I think).
Win32 also supports ‘/’ in most cases. Not sure about MacOS.


File security is pretty much non-existant on most target win32 systems
(except NT). Unix-based systems are a lot more strict. You can’t always
assume you’ll be able to open a specific file for writing. eg if you’ve
installed you game data files anywhere other than the users homedir
chances are that it’ll be read-only access.


Make sure all your #include paths are the correct case (ie #include
<stdio.h> instead of #include
<StdIO.h>) and use forward-slash (’/’) instead of back-slash (’’) path
separators.


And of course, C++ is still a bit of a moving target as far as
portablity goes - sticking with ANSI C is good if you can get away with
it :slight_smile:


Phew.
Hope all this is of interest to someone! Feedback most welcome.
BTW anyone else in this newsgroup going to GDC in march?

Ben.


Ben Campbell (Antipodean Straggler)
Programmer, Creature Labs
ben.campbell at creaturelabs.com
www.creatures.co.uk

We’re using C++, primary platform is win32, Visual C/C++. I’ve been
doing stuff with the latest gcc versions under Linux. MacOS, OSX,
Playstation 2, Codewarrior are also platforms/tools of interest, but I
haven’t done any serious research on them.

Here is what I’ve come up with so far - I’d love it if people had
items to add :slight_smile:

BTW folks, this is VERY good stuff. Many of the items listed we’ve
run into here at Loki.

A few more (off the top of my head)

Carefully design your code so it is both fast and platform independent.
This is a magic science, probably one of those "a lifetime to master"
things. :slight_smile:

Don’t assume anything about the memory layout of structures. Use the
structure members explicitly. If you find yourself using unions, you
may want to reconsider - it will be painful when you port to gcc.

Keep endianness in mind, especially when designing your network code. :slight_smile:

I may think of more after a good morning’s sleep. :slight_smile:

See ya!
-Sam Lantinga (slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

Ben Campbell wrote:


gcc (2.95.2) bugette:

bool wibble()
{
printf(“Wibble!\n”);
}

gcc doesn’t seem to mind the lack of return value.

It goes even one step further - the below code works correctly on gcc :slight_smile:

int clamp(int x, int width)
{
if (x<0)
return 0;
if (x>=width)
return width -1;
// return x;
}–
Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

It goes even one step further - the below code works correctly on gcc :slight_smile:

int clamp(int x, int width)
{
if (x<0)
return 0;
if (x>=width)
return width -1;
// return x;
}

It will warn you if you include -Wall (like you always should). Still, if
it knows there’s a problem, why doesn’t it do more about it? :slight_smile:

Paul Braman
@Paul_BramanOn Sun, 20 Feb 2000, Daniel Vogel wrote:

Sam Lantinga wrote:

A few more (off the top of my head)

Even more…

VC++ doesn’t properly scope variables declared in for statements.

VC++ doesn’t support covariant return types (which were the first
extension proposed to the standardization committee, accepted in 1992).

Using declarations can be somewhat flaky on VC++.

Same for templates. I couldn’t template on a pointer-to-member-function
without getting an internal compiler error.

The STL is entirely broken under VC++, for legal reasons. Use STLport.
GCC uses SGI’s STL, but is currently missing some bits of the rest of
the standard library.

GCC is currently not strict about requiring std:: scoping.

I’d say always write your own random number generator, never trust the
system one. But make sure you copy a good one.

Watch out for: size and layout of memory, endianness, file paths, thread
scheduling, etc.–
Marc A. Lepage
http://www.antimeta.com/
Minion open source game, RTS game programming, etc.

Daniel Vogel wrote:

Ben Campbell wrote:


gcc (2.95.2) bugette:

bool wibble()
{
printf(“Wibble!\n”);
}

gcc doesn’t seem to mind the lack of return value.

It goes even one step further - the below code works correctly on gcc :slight_smile:

int clamp(int x, int width)
{
if (x<0)
return 0;
if (x>=width)
return width -1;
// return x;
}

-Wall (misleadingly IMO) doesn’t turn on all warnings. Check the man
pages and turn then all on, then try.–
Marc A. Lepage
http://www.antimeta.com/
Minion open source game, RTS game programming, etc.

“Marc A. Lepage” wrote:

It goes even one step further - the below code works correctly on gcc :slight_smile:

int clamp(int x, int width)
{
if (x<0)
return 0;
if (x>=width)
return width -1;
// return x;
}

-Wall (misleadingly IMO) doesn’t turn on all warnings. Check the man
pages and turn then all on, then try.

I was rather fascinated by the fact that it not only compiles but WORKS
(looks like the stack doesn’t get cleaned properly without the return
and the int x gets popped as return value - didn’t have a look at the
assembler output, though).–
Daniel Vogel My opinions may have changed,
666 @ http://grafzahl.de but not the fact that I am right

VC++ doesn’t properly scope variables declared in for statements.

I think that’s not true: at least the latest ISO (ANSI?) C++ standard
defines variables declared in for statements in the scope the for statement
is in so you can do:
for (int i=0; i<10; i++ )
;// blah
if ( i==10 )
// we didn’t break out of the loop

Anyway the other points are very good IMO.
Just wanted to stress the advice not to use structures for loading
eg for file header loading because structure layout is different on
every system and each compiler has its own syntax to do structure
packing :slight_smile:

~ Paulus Esterhazy (@Paulus_Esterhazy)

I think that’s not true: at least the latest ISO (ANSI?) C++ standard
defines variables declared in for statements in the scope the for statement
is in so you can do:
for (int i=0; i<10; i++ )
;// blah
if ( i==10 )
// we didn’t break out of the loop

I recently helped my brother troubleshoot a problem like this in VC++.

for (int i=0; i<10;i++)
{
// do your stuff here
}

if (i == 10)
{}
Did not work.
The ‘i’ was available in the scope of the for loop, but not outside of it.
I’m not saying this is wrong or even non-standard. I’m just saying this
is how it seemed to work in VC++.

If I had VC++, I would have verified this before emailing… but I guess
I’ll have to stick my head out this time before verifying it again.–
Brian

Paulus Esterhazy wrote:

VC++ doesn’t properly scope variables declared in for statements.

I think that’s not true: at least the latest ISO (ANSI?) C++ standard
defines variables declared in for statements in the scope the for statement
is in so you can do:
for (int i=0; i<10; i++ )
;// blah
if ( i==10 )
// we didn’t break out of the loop

Anyway the other points are very good IMO.

You are absolutely incorrect.

My (final) copy of ISO/IEC 14882-1998 says:

----- BEGIN QUOTE -----
3.3.2 Local scope [basic.scope.local]

Names declared in the for-init-statement, and in the condition of if,
while, for, and switch statements are local to the if, while, for, or
switch statement (including the controlled statement), and shall not be
redeclared in a subsequent condition of that statement nor in the
outermost block (or, for the if statement, any of the outermost blocks)
of the controlled statement; see 6.4.
----- END QUOTE -----

It’s been that way for a long time. See “The Design and Evolution of
C++” for details. I also believe that playing with loop variables after
the loop is poor style.

Just wanted to stress the advice not to use structures for loading
eg for file header loading because structure layout is different on
every system and each compiler has its own syntax to do structure
packing :slight_smile:

Yes even subsequent revisions of the same compiler may change layout.
Compiler flags may change layout. Do people really still do this?–
Marc A. Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/

hayward at slothmud.org wrote:

I think that’s not true: at least the latest ISO (ANSI?) C++ standard
defines variables declared in for statements in the scope the for statement
is in so you can do:
for (int i=0; i<10; i++ )
;// blah
if ( i==10 )
// we didn’t break out of the loop

I recently helped my brother troubleshoot a problem like this in VC++.

for (int i=0; i<10;i++)
{
// do your stuff here
}

if (i == 10)
{}
Did not work.
The ‘i’ was available in the scope of the for loop, but not outside of it.
I’m not saying this is wrong or even non-standard. I’m just saying this
is how it seemed to work in VC++.

If I had VC++, I would have verified this before emailing… but I guess
I’ll have to stick my head out this time before verifying it again.

The issue is, VC++ INCORRECTLY injects i into the scope enclosing the
for statement. The above code SHOULD work on VC++, but is poor style and
should NOT work on a conforming compiler.

I have to use this idiom to make my code work on GCC and VC++:

for (int i = 0; i < 10; ++i)
{
// first loop
}

{for (int i = 0; i < 10; ++i)
{
// second loop
}}

PS: always use preincrement unless you need the original value of the
variable.–
Marc A. Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/

Scope of variables, I know from discussions with others there are
quite a few opinions on this subject. My personal opinion is that
for,while,do, etc… are scope modifiers, and that variables defined
within that scope should go out of scope when exiting the scope
statement.

example 1: (one reason why i should go out of scope)

function()
{

for(int i = 0; i<=10; (i++)) //yes I did (i++) for a reason
{

}
// are you really sure you know what value i will have if it is still
// in scope?
if(i==10) cout << “i is still in scope (bad) and equals 10” << endl;
if(i==11) cout << “i is still in scope (bad) and equals 11” << endl;
}

example 2: (based on the C explination of variable scope from K&R C)
function() // this code should be valid, not good coding though.
{
int i = 1;

for(int i = 0; i < 3; i++)
{
for(int i = 2; i < 5; i++)
{
// nop
}
}
}

And the third point is if you make yourself a little stack machine and
run through your code (on paper is fine), you can see why it should go
out of scope based on how a stack machine works.=====
Jason Platt.

“In theory: theory and practice are the same.
In practice: they arn’t.”


Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.

And the third point is if you make yourself a little stack machine and
run through your code (on paper is fine), you can see why it should go
out of scope based on how a stack machine works.

Could you take this off-topic discussion offline?

Thanks!
-Sam Lantinga (slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

Jason Platt wrote:

Scope of variables, I know from discussions with others there are
quite a few opinions on this subject. My personal opinion is that
for,while,do, etc… are scope modifiers, and that variables defined
within that scope should go out of scope when exiting the scope
statement.

It’s not a question of personal belief. I just posted the relevant
section of the C++ standard! VC++ is outdated and incorrectly scopes
variables declared in the conditions of for statements. This is a
porting issue that any significant body of code will tickle.

example 1: (one reason why i should go out of scope)

function()
{

for(int i = 0; i<=10; (i++)) //yes I did (i++) for a reason
{

}
// are you really sure you know what value i will have if it is still
// in scope?
if(i==10) cout << “i is still in scope (bad) and equals 10” << endl;
if(i==11) cout << “i is still in scope (bad) and equals 11” << endl;
}

Yes. It will be 10. Preincrement and postincrement have the exact same
(relevant) semantics in the above code. The loop counting is the same in
either case.

example 2: (based on the C explination of variable scope from K&R C)
function() // this code should be valid, not good coding though.
{
int i = 1;

for(int i = 0; i < 3; i++)
{
for(int i = 2; i < 5; i++)
{
// nop
}
}
}

On old compilers (like VC++) this will not work, as you point out. In
this case, the variables are different and should have different names.
But in other cases, for example going through an array twice in a
function, the variables are the same and I prefer them to have the same
name. That’s why I work around the problem by adding extra scoping and
not by coercing variable names to be different.

And the third point is if you make yourself a little stack machine and
run through your code (on paper is fine), you can see why it should go
out of scope based on how a stack machine works.

This isn’t true. It never used to be this way. Originally, it WAS in the
enclosing scope. So it clearly isn’t necessary that it not be in the
enclosing scope.

See “The Design and Evolution of C++” for details. That’s a great book
BTW. It isn’t boring academic reading, it’s a great look at why the
language is the way it is, and how it could have been and why it isn’t,
with practical results immediately evident.–
Marc A. Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/

Sam Lantinga wrote:

[re scope of variables declared in for statements]

Could you take this off-topic discussion offline?

Yes please. It’s beaten to death anyways.–
Marc A. Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/