C portability is a myth

W

websnarf

Flash said:
Actually C provides exactly *one* method of interfacing to libraries.
It's just what libraries are available that varies. However, there are
cross platform GUIs.

That are actively maintained, actually function, work in C (not C++)
and which have non-trivial availability?
It was developed on a 16 bit system and is currently used on
32 bit systems of both endiannesses.

So I'll take that as a no.

I thought my bignum library was complete long time ago -- it works on
16, and 32 bits under assumption that the underlying "int" is 16, 32 or
64 bits. But my Euler totient function is going crazy on at least one
pure 64 bit system with 64 bit scalars for numbers of with around 100
bits. Its damn annoying, but I've got it narrowed down (its not the
factoring or primality testing, so its somewhere in the glue code), and
this looks like the final bug.

Even for something as simple as "The Better String Library", I had to
waste about a day to make it port to all the various platforms I have
access to. And that's a library I had high confidence was portable
right out of the box. Of course it was the C standard itself which was
the culprit in causing the porting problems (vsnprintf being available
on only some systems, and having wildly different return value
semantics even on systems that do support it -- and *blaming* a
compiler vendor doesn't get me any closer to a successful port).
Not if you know what you are doing. This code took no extra
effort. In fact, I did not even think about portability. It
just worked.

Ok, but I am willing to bet that our code simply isn't comparable. For
example, my BigInt library is totally compatible with all the 2s
compatible tricks from HAKMEM, uses aggressive methods for tesing
primality and factoring numbers, and fully supports parameters aliasing
with some sort of attention being paid to efficiency. Its not as easy
as you may think.
Sounds like the code was badly written.

On what grounds do you say this? The algorithms are complicated, and
if I expect to have any hope of efficiency for large numbers, I have to
pay a lot of attention to exact representation of the scalars used.
I've used the "limits.h" constants everywhere, but that just isn't
enough.
It does not take me vast amounts of extra effort.

Well, if you are writing command line text utilities for UNIX that
assume total input is less than 64K, I am not surprised. Let me know
when you've got a Windows 3.1 and Mac OS 9 port of your application
done.
If it follows the standard, then it is compatible with all
other C compilers that follow the standard.

This is the most ridiculous thing I've ever heard. I have never
encountered any pair of C compilers that I couldn't write natural fully
ANSI compliant code for that produced two entirely different results.
The ANSI C standard itself does not specify a model for what the output
is supposed to do that is in any sense portable.

And I've got 4 different 32-bit x86 C compilers that all produce Win32
code installed on my machine -- we're talking about the exact same
platform, all compliant with the exact same version of the ANSI C
standard -- its sad, no two of them generate the same semantic results
for generic C code. Writing useful Open Source, even if I am just
targetting Win32 on x86 requires writing the code, then porting it *3
times* (or doing the typical lame cop out of telling everyone to use
gcc).
[...] If not, then you still have a "C" compiler targeting
all systems with a Java implementation where all such
implementations will behave as closely for C as they do for
Java, thus making C at least as portable as Java by your
definition.

No, it makes *THAT* C compiler (which is OT on comp.lang.c, BTW)
portable. That's sort of like saying C is portable so long as you just
use gcc.
So you keep saying.

So you (and others) keep ignoring. Look, I given a link to an online
dictionary definition. I don't know what else to do.
[...] However, you fail to understand that portability is the
ability to port to different systems, therefore lack of an
implementation (or sufficiently functional implementation) on
all platforms is a limiting factor on portability.

No, its a limiting factor on availability. Whether or not code is
portable is a charactistic of the code, or the language that the code
conforms to, and nothing more.
That does not stop availability being a limiting factor on
portability.

Availability is a limiting factor to availability. It has nothing to
do with portability.
[...] How about the Perl implementation? This processor
only has a *maximum* of 64K program address space and 64K
data address space and our target HW had at most 8K of each.

Dunno, but you should try out LUA on it. Either way I don't
think that processor will ever be able to run my (or any other
serious) multiprecision integer library.

I don't think your desktop PC will ever be certified to be fitted
in a military jet. Your point is?

My point is that since the ANSI C standard *itself* abandons
portability as any kind of goal, of course it can be implemented
anywhere by sheer brute force effort. Of course "BASIC" had this exact
same property. The fact that you can run a C compiler on that platform
doesn't say *anything* about portability -- because the limiting factor
to the portability is going to be the capabilities of that platform.
The ANSI C standard cannot make that platform portable, and neither
does the availability of a C compiler for it. Most code isn't portable
to this lame device because the platform can't run any sort of portable
execution environment on it.

When I worked at a start up, we created a hardware device with lots of
severe limitations and weirdnesses about it as well. Some of the
developers insisted that we needed to port a C compiler to it, but we
aborted half-way through the effort and instead ended up with a
language we called "V", which was some C-like thing, but was really
more taylored to the capabilities and limitations of the chip. While
some developers still wanted the language to evolve to C, the vast
majority of us recognized that that simply didn't add any real value
add -- certainly it would not give us any hope of portability with
*any* other C platform.

For a platform as small as that, chances are C is just the wrong
language for it. It seems comparable to an APPLE ][ or Commodore 64.
And on that kind of a platform, a language like Forth seems more
appropriate.
 
O

Old Wolf

I thought my bignum library was complete long time ago -- it works on
16, and 32 bits under assumption that the underlying "int" is 16, 32 or
64 bits. But my Euler totient function is going crazy on at least one
pure 64 bit system with 64 bit scalars for numbers of with around 100
bits. Its damn annoying, but I've got it narrowed down (its not the
factoring or primality testing, so its somewhere in the glue code), and
this looks like the final bug.

So you wrote buggy code. Whose fault is that?
Of course it was the C standard itself which was
the culprit in causing the porting problems (vsnprintf being available
on only some systems, and having wildly different return value
semantics even on systems that do support it -- and *blaming* a
compiler vendor doesn't get me any closer to a successful port).

There is no function 'vsnprintf' in ANSI C. So it can
hardly be the fault of the C standard.

If you are talking about ISO C99, then there is only one
vsnprintf, and its return value is defined by that
standard. Any other return value is non-conforming, and so
either the vendor's fault, or your fault for assuming your
compiler was C99 compliant when it wasn't.
 
S

Stephen Sprunk

They are different compontents related by a problem manifested by the C
language standard. Namnely: can you compile and run a given set of C
source code. Having a compiler on a platform is supposed to give you
some hope that its possible, but the path is usually convoluted unless
the program is extremely trivial (like a Unix text processing utility.)

I and others have cited nontrivial C projects that are portable.
Look, the distinction is just a matter of english:

When one "ports" a piece of code, one is not talking about the
solicitation for the availability of a compiler for a given platform.
One is implicitely assuming there is some other target platform with a
different compiler, and one engages in the activity of "porting"
(changing the code -- not installing some compiler.)

One cannot port code to a system that has no compiler or JVM available.
There are additional components to porting, but the first step is
availability.
When an application becomes "ported", this means that the application
has been modified (including the rare possibility of no changes.)
Nobody would say an application becomes "ported" when a new platform or
compiler becomes available and the sources happen to work on it.

When I say code is "ported", that means I've compiled and tested the code on
the new platform and it appears to work. If the source is pure Standard C
with no extensions or abuse of UB or IDB, then I can be sure my code is
_portable_.

"Porting" is typically painful because most C source is not strictly
compliant with the standard or uses extensions or libraries that are not
available on the new platform. That is not C's fault -- it's the
programmer's for straying from the Standard.

Of course, one can complain the Standard doesn't cover enough features to be
useful to you, but every feature added will inevitably reduce the
availability of conforming implementations.
When one uses a "portability layer" they are not referring to something
like a "compiler emulator" or cross compiling, or some kind of compiler
detection. Its usually a library module, or source modification tool
that makes a body of code be of such a manifestation that it can run on
multiple platforms more easily irrespective of compiler availability.

That "portability layer" is an attempt to cover up the use of extensions or
libraries that are not actually part of Standard C.
If I am "porting" a piece of code or library, I am not trying to make a
compiler available on a platform. I am just in the process of
modifying it to make it work on a target platform. A system developer
might port a compiler or generate one for a new system, but this is a
port in of itself for the purpose of making a compiler available. For
example when AMD and SUSE first ported gcc over to AMD64, they
didn't take credit for "porting" the rest of the open source universe to
their platform;

Of course not; porting a compiler does not imply porting anything else.
However, it is a necessary step before one _can_ port anything else.
and the ANSI C standard can't take credit for it either --
because after that was done each application then had to be "ported"
all over again

And the work required for each port depends directly on how far the code in
question has deviated from the Standard.
(because there's no guarantee that they'll work -- you
have to test it).

Yes, testing is a part of porting code.
Now if one creates a JVM for a platform (thus making it "available"),
does that mean they have "ported" all the Java applications onto that
platform?

Not until you've run and tested all of them -- and they work.
At best you can say that the Java *standard* ported the
applications.

As others have said, just because an app is written in Java doesn't mean it
can be successfully ported to all implementations.

Standard C source is portable to all conforming implementations because, by
definition, an implementation is conforming only if it correctly translates
Standard C source. Your problem seems to be with code that is _not_
Standard C or with implementations that are _not_ conforming.

S
 
S

Stephen Sprunk

That are actively maintained, actually function, work in C (not C++)
and which have non-trivial availability?

Depends what you consider non-trivial.
So I'll take that as a no.
And?

I thought my bignum library was complete long time ago -- it works on
16, and 32 bits under assumption that the underlying "int" is 16, 32 or
64 bits.

That's an unportable assumption. But, of course, if one only cares about
portability to systems where it's true, it's a reasonable one, but the code
still isn't portable.
But my Euler totient function is going crazy on at least one
pure 64 bit system with 64 bit scalars for numbers of with around 100
bits. Its damn annoying, but I've got it narrowed down (its not the
factoring or primality testing, so its somewhere in the glue code), and
this looks like the final bug.

I'm sure someone here would be happy to help you with that.
Even for something as simple as "The Better String Library", I had to
waste about a day to make it port to all the various platforms I have
access to.

Depending on how long it took to write in the first place, that may not be
bad. It's easy to fall into the habit of writing unportable code the first
time, and in my experience it takes a lot more effort to get it right later.
And that's a library I had high confidence was portable
right out of the box. Of course it was the C standard itself which was
the culprit in causing the porting problems (vsnprintf being available
on only some systems, and having wildly different return value
semantics even on systems that do support it -- and *blaming* a
compiler vendor doesn't get me any closer to a successful port).

That's not the Standard's fault, as Old Wolf explains.
Ok, but I am willing to bet that our code simply isn't comparable.

Nope -- yours obviously isn't portable.
For example, my BigInt library is totally compatible with all the 2s
compatible tricks from HAKMEM, uses aggressive methods for tesing
primality and factoring numbers, and fully supports parameters aliasing
with some sort of attention being paid to efficiency. Its not as easy
as you may think.

If it's not easy, you're probably relying on undefined or
implementation-defined behavior.
On what grounds do you say this? The algorithms are complicated, and
if I expect to have any hope of efficiency for large numbers, I have to
pay a lot of attention to exact representation of the scalars used.
I've used the "limits.h" constants everywhere, but that just isn't
enough.

If you need to know the exact representation of integers, your code isn't
portable.

Now, that may result in the fastest execution on platforms you've ported the
code to, but it means you'll have more trouble porting it to new ones.
This is the most ridiculous thing I've ever heard. I have never
encountered any pair of C compilers that I couldn't write natural fully
ANSI compliant code for that produced two entirely different results.
The ANSI C standard itself does not specify a model for what the output
is supposed to do that is in any sense portable.

Then either at least one of the compilers is nonconforming or you are
mistaken about the code being compliant.
[...] How about the Perl implementation? This processor
only has a *maximum* of 64K program address space and 64K
data address space and our target HW had at most 8K of each.

Dunno, but you should try out LUA on it. Either way I don't
think that processor will ever be able to run my (or any other
serious) multiprecision integer library.

I don't think your desktop PC will ever be certified to be fitted
in a military jet. Your point is?

My point is that since the ANSI C standard *itself* abandons
portability as any kind of goal, of course it can be implemented
anywhere by sheer brute force effort.

It doesn't abandon portability; it just defines a fairly limited set of
features that are portable.
The fact that you can run a C compiler on that platform doesn't say
*anything* about portability -- because the limiting factor
to the portability is going to be the capabilities of that platform.

If the implementation is conforming, the Standard says quite a bit about
what the capabilities are.
The ANSI C standard cannot make that platform portable, and neither
does the availability of a C compiler for it. Most code isn't portable
to this lame device because the platform can't run any sort of portable
execution environment on it.

If the platform cannot support a conforming C implementation, then of course
portability will be a problem.
For a platform as small as that, chances are C is just the wrong
language for it. It seems comparable to an APPLE ][ or Commodore 64.
And on that kind of a platform, a language like Forth seems more
appropriate.

Use the best tool for the job. If it's not C, so be it, but that's
off-topic here.

S
 
F

Flash Gordon

That are actively maintained, actually function, work in C (not C++)
and which have non-trivial availability?

I'll start you off with GTK+. I use applications based on this on both
Windows and Linux so it provides at least a degree of portability.
So I'll take that as a no.

No one currently wants to run it on either 8 or 64 bit systems or
systems with 64K of memory. When they do I'll let you know. In the mean
time, how many JVMs can you find for 8 bit systems?
I thought my bignum library was complete long time ago -- it works on
16, and 32 bits under assumption that the underlying "int" is 16, 32 or
64 bits. But my Euler totient function is going crazy on at least one
pure 64 bit system with 64 bit scalars for numbers of with around 100
bits. Its damn annoying, but I've got it narrowed down (its not the
factoring or primality testing, so its somewhere in the glue code), and
this looks like the final bug.

So you have a bug in your code where you are either invoking undefined
behaviour or implementation defined behaviour without dealing with all
possible implementations. That is your problem.
Even for something as simple as "The Better String Library", I had to
waste about a day to make it port to all the various platforms I have
access to. And that's a library I had high confidence was portable
right out of the box. Of course it was the C standard itself which was
the culprit in causing the porting problems (vsnprintf being available
on only some systems, and having wildly different return value
semantics even on systems that do support it -- and *blaming* a
compiler vendor doesn't get me any closer to a successful port).

So you use a function from the latest standard that has approximately
one conforming implementation. That is your problem. Had you stuck to
C89 it would not have been a problem.
Ok, but I am willing to bet that our code simply isn't comparable.

It stated "but it takes a lot of effort" and I presented a counter
example where no effort was required because none was spent. To disprove
any absolute statement you one need to provide *one* counter example. It
was a non-trivial piece of code with a carefully optimised *design*.
> For
example, my BigInt library is totally compatible with all the 2s
compatible tricks from HAKMEM, uses aggressive methods for tesing
primality and factoring numbers, and fully supports parameters aliasing
with some sort of attention being paid to efficiency. Its not as easy
as you may think.

So you are saying that because you rely on things explicitly stated by
the standard as being up to the implementation it prevents everything
the language defines as being portable from being portable?
On what grounds do you say this? The algorithms are complicated, and
if I expect to have any hope of efficiency for large numbers, I have to
pay a lot of attention to exact representation of the scalars used.
I've used the "limits.h" constants everywhere, but that just isn't
enough.

If you are having problems porting it then it obviously has a lot of
dependencies on either implementation defined or undefined behaviour
which are not properly documented.
Well, if you are writing command line text utilities for UNIX that
assume total input is less than 64K, I am not surprised. Let me know
when you've got a Windows 3.1 and Mac OS 9 port of your application
done.

Currently one piece of SW is running on SCO 5.0.3 through to SCO 5.0.7,
AIX 4.3, AIX 5 (well, tested but not currently used by customers),
Windows NT/XP. One of the platforms at the start was DOS. It has also
run on HP-UX and Solaris. I've previously mentioned software I had
running unchanged on a DSP processor and a Silicon Graphic Workstation.

We've had to tell some of our customers to upgrade to at least SCO 5.0.6
because the JVMs available for earlier version of SCO do *not* run a
*Java* application they also want to use.
This is the most ridiculous thing I've ever heard. I have never
encountered any pair of C compilers that I couldn't write natural fully
ANSI compliant code for that produced two entirely different results.
The ANSI C standard itself does not specify a model for what the output
is supposed to do that is in any sense portable.

Well, I have non-trivial code that behaves the same. I also know that
Berkeley DB (a very non-trivial application) is written in C and that
runs the same on a wide range of systems.
And I've got 4 different 32-bit x86 C compilers that all produce Win32
code installed on my machine -- we're talking about the exact same
platform, all compliant with the exact same version of the ANSI C
standard -- its sad, no two of them generate the same semantic results
for generic C code. Writing useful Open Source, even if I am just
targetting Win32 on x86 requires writing the code, then porting it *3
times* (or doing the typical lame cop out of telling everyone to use
gcc).

You obviously rely heavily on things not guaranteed by the standard. I'm
sure that if you use ActiveX in Java (which I'm told is possible) you
will have great difficulty getting that Java code to work on Linux.
[...] If not, then you still have a "C" compiler targeting
all systems with a Java implementation where all such
implementations will behave as closely for C as they do for
Java, thus making C at least as portable as Java by your
definition.

No, it makes *THAT* C compiler (which is OT on comp.lang.c, BTW)
portable. That's sort of like saying C is portable so long as you just
use gcc.

I've got this Java 1.3 JVM, can I run your Java application developed
for Java 1.4? Not sodding likely. Therefore *exactly* the same can be
said about Java.
So you (and others) keep ignoring. Look, I given a link to an online
dictionary definition. I don't know what else to do.

http://dictionary.reference.com/search?q=portability
"Computer Science. Relating to or being software that can run on two
or more kinds of computers or with two or more kinds of operating systems."

If an implementation is not available for a system then you can't run
the application on it, therefore it is not portable to that system,
therefore that is a limit on portability.

http://onlinedictionary.datasegment.com/word/portability also agrees and
even states C as probably being the most portable language.
[...] However, you fail to understand that portability is the
ability to port to different systems, therefore lack of an
implementation (or sufficiently functional implementation) on
all platforms is a limiting factor on portability.

No, its a limiting factor on availability. Whether or not code is
portable is a charactistic of the code, or the language that the code
conforms to, and nothing more.

As stated previously and not addressed by you. That means that any code
written for a language with exactly one implementation is, by
definition, completely portable even though it only runs on the one
system. That is obviously complete rubbish.
Availability is a limiting factor to availability. It has nothing to
do with portability.

See above. By your definition you can have a completely portable program
that runs on exactly one machine. Your definition also makes something
like TMS320C25 machine code extremely portable since any TMS320C25 will
run the machine code exactly the same.
[...] How about the Perl implementation? This processor
only has a *maximum* of 64K program address space and 64K
data address space and our target HW had at most 8K of each.

Dunno, but you should try out LUA on it. Either way I don't
think that processor will ever be able to run my (or any other
serious) multiprecision integer library.

I don't think your desktop PC will ever be certified to be fitted
in a military jet. Your point is?

My point is that since the ANSI C standard *itself* abandons
portability as any kind of goal, of course it can be implemented
anywhere by sheer brute force effort.

No, it tells you exactly what will work on all systems thus allowing you
to write portable code. It also tells you where the implementation has
to tell you about choices if you have good reason to do something
dependant on those implementation choices.
> Of course "BASIC" had this exact
same property. The fact that you can run a C compiler on that platform
doesn't say *anything* about portability -- because the limiting factor
to the portability is going to be the capabilities of that platform.
The ANSI C standard cannot make that platform portable, and neither
does the availability of a C compiler for it. Most code isn't portable
to this lame device because the platform can't run any sort of portable
execution environment on it.

None of which makes C any less portable than any other language. If you
find a machine which only had 4K of RAM available once the JVM is loaded
it will find it rather difficult to run a 500K Java application.

You can't say that platform limitations such as amount of memory are
applicable to C portability but not to portability of any other
language. Well, you can, but it just shows you to be trolling.
When I worked at a start up, we created a hardware device with lots of
severe limitations and weirdnesses about it as well. Some of the
developers insisted that we needed to port a C compiler to it, but we
aborted half-way through the effort and instead ended up with a
language we called "V", which was some C-like thing, but was really
more taylored to the capabilities and limitations of the chip. While
some developers still wanted the language to evolve to C, the vast
majority of us recognized that that simply didn't add any real value
add -- certainly it would not give us any hope of portability with
*any* other C platform.

So? Did you write a JVM for the chip? If not it is completely irrelevant
to the relative portability of C and Java. If the only language
available for it is your V language, and your V language is only
available for that chip, then why not write all your SW in V as, by your
definition (which no one else seems to agree with) and code written in V
is by definition complete portable.
For a platform as small as that, chances are C is just the wrong
language for it. It seems comparable to an APPLE ][ or Commodore 64.
And on that kind of a platform, a language like Forth seems more
appropriate.

Your point is? Are you now saying that it is Forth which is portable
rather than Java or C?
 
W

websnarf

Flash said:
I'll start you off with GTK+. I use applications based on this on
both Windows and Linux so it provides at least a degree of
portability.

But wait -- C compilers are available everywhere. Doesn't that make
GTK+ portable everywhere as well? Would you say GTK+'s degree of
portability has to do with availability, or with the
contents/characterists of the code?
So you have a bug in your code where you are either invoking
undefined behaviour or implementation defined behaviour without
dealing with all possible implementations. That is your problem.

Yes but the language encourages these sorts of bugs -- that's the
problem. I am not convinced yet that it isn't a compiler bug (I saw
one of those a couple days ago in unrelated code, but with the same
compiler.) You also have to understand -- this "bug" is not following a
NULL pointer, or assuming struct alignment, or buffer overflow or
something like that. Its some kind of really twisted numerical
interaction.

Besides you are missing the point. I've gone to quite a bit of trouble
to make this code portable. I had high hopes that after a couple ports
everything else would just click and I'd be done. But every platform
and every compiler has presented a unique problem. For example do you
know what the following does: double d = (double)1844674407370955161ULL
? Hint: Its not just a "slight" precision loss.
So you use a function from the latest standard that has
approximately one conforming implementation.

But how am I to know this? The standard where this function was
introduced is extremely old. My natural assumption was that it was
there. Its certainly there for many compilers. I don't think Java has
that degree of laziness -- the compiler asserts a version, and
everything in the standard for that version is either in there, or the
compiler is just non-compliant, and Sun sues you if you claim
otherwise.
[...] That is your problem. Had you stuck to C89 it would not
have been a problem.

2005-1989 = 16 years old, and apparently I cannot expect better than
that from the C standard. Tell me this is not an indictment of the
standard or the committee behind it.
You stated "but it takes a lot of effort" and I presented a
counter example where no effort was required because none was
spent. To disprove any absolute statement you one need to
provide *one* counter example. It was a non-trivial piece of code
with a carefully optimised *design*.

Your logic is broken. I did not say or imply that *every* piece of
code was hard to port. I was discussing code that *I* write (hence a
reference to *my* effort). I don't write a lot of command line UNIX
based text processing utilities.
So you are saying that because you rely on things explicitly
stated by the standard as being up to the implementation it
prevents everything the language defines as being portable from
being portable?

Unless you have tested all your code on a 1s complement machine, your
question is completely moot. I have hard time believing that more than
0.001% of any C developers have ever written code that they can
definitively assert as "portable". The standard enshrines the ability
for literally a handful of extremely marginal architectures to be able
to *COMPILE* any conforming C code to their paradigm -- a completely
ridiculous stand, considering that basically nobody has access to these
machines any more, and even after compiling, the code may do who knows
what as a result.

Porting requires effort regardless of whether or not I have conformed
to the ANSI C standard, and regardless of whether or not I have made
assumptions about implementation specific representations. Conforming
to the ANSI C standard is not a path towards portability, it only
catches the most egregious deviations as well as deviations that just
don't matter in the real world.
If you are having problems porting it then it obviously has a
lot of dependencies on either implementation defined or
undefined behaviour which are not properly documented.

Well, I wasn't relying on any undefined behavior; it all did come down
to implementation specific stuff, of course, that's the whole point.
Currently one piece of SW is running on SCO 5.0.3 through to
SCO 5.0.7, AIX 4.3, AIX 5 (well, tested but not currently used
by customers), Windows NT/XP. One of the platforms at the
start was DOS. It has also run on HP-UX and Solaris. I've
previously mentioned software I had running unchanged on a DSP
processor and a Silicon Graphic Workstation.

I see, so Win3.1 and Mac OS 9 are simply too difficult for you?
Well, I have non-trivial code that behaves the same. I also know
that Berkeley DB (a very non-trivial application) is written in C
and that runs the same on a wide range of systems.

I have some fairly recent Berkely DB sources (maybe a year old; they
make reference to Mac OS X in the comments). Here's a quick summary:

1. Its incorrect w.r.t. namespace pollution (they use symbols with
leading _ littered all over the place.) Its at least partially written
with K&R prototypes.

2. It contains the following sub-directories: build_unix,
build_vxworks, build_win32 which contains loads of c code for platform
specific details. Certainly there exists no compiler that can
successfully compile all of those sources to product one common
semantic result. It also contains a directory called clib for dealing
with non-conforming C compilers on multiple modes of failurr for at
least 10 different C library functions. There is a function that tests
for endianness on the fly.

3. In dbinc/lock.h we can plainly see that DB_LOCK_MAXID is just
defined to 0x7fffffff in the raw. Other examples of this nonsense
include DB_LOCK_DOALL, DB_LOCK_FREE, etc -- they didn't even have the
good sense to put "UL" on the end of these constants. You think they
plan on porting this to a 16 bit compiler any time soon? dbinc/mutex.h
is filled with nothing but inline assembly (and there is no coverage
for 16 bit DOS compilers, or Win 3.1 or Mac OS 9)

In short, the code is not portable -- it has been ported, by sheer
brute force, to 3 platforms: Mac OS X/Linux/Unix, VxWorks and Windows.
It looks like about 10-20% of the sources have been dedicated
specifically dealing with porting issues and they were obviously very
laborious exercises (almost comparable to trying to make a portable
BigInt library.) And I'm not sure of what the OS/2, or VMS or DOS, or
QNX people think of this, but they don't seem to have a voice here. I
mean berkely db really represents a simple idea that looks like the
only really challenging thing going on is dealing with mollasses
created by the exercise of porting it.

In short Berkeley DB is actually a primary example of why C is *not* a
portable language. It also a demonstration of "port by brute force"
and just why it is so hard to get portabiity correct (because they
faied pretty badly here.)

Of course they include a Java interface as well -- interesting that
they don't seem to have any subdirectories or special files dealing
with differences in JVMs.
For a platform as small as that, chances are C is just the
wrong language for it. It seems comparable to an APPLE ][
or Commodore 64. And on that kind of a platform, a language
like Forth seems more appropriate.

Your point is? Are you now saying that it is Forth which is
portable rather than Java or C?

No *YOU* are the one bringing this marginal example in to this
discussion about portability. For a device as small as that, you
aren't going to port anything serious to it at all regardless of
language. I am just making the point the targetting a C compiler to
the device is a pointless exercise as resources are at an extreme
premium. Other languages like Forth are norotious for having extremely
small footprints and would probably be better for it. Making a C
compiler available on there doesn't give you any seriously hope of
porting anything that couldn't be written in a short time from scratch,
and more usefully in a language taylored to that device.

The example of the device *I* was talking about is an example of the
same thing but is more extreme -- because our chip certainly *COULD*
have been targetted by a compliant C compiler and might have accepted
lots of compliant code, it would just have been insanely useless to do
so.
 
W

websnarf

Stephen said:
Depends what you consider non-trivial.

Ok, first of all to be considered "ported" you just need two platforms.
To be considered "portable", in the case of GUIs, I would consider
non-trivial coverage to mean comparable to the set of platforms that
Open GL has been ported to. (Open GL is not a GUI, BTW)
That's an unportable assumption.

I am describing what I knew worked, not what I think the only possible
representations of ints were. This is just the situtation as I knew it
before I started serious testing a 64 bit platform.
[...] But, of course, if one only cares about portability to
systems where it's true, it's a reasonable one, but the code
still isn't portable.

Agreed, and correct. That's the whole point. My goal is to be
universally portable, however, not to limit it to just the platforms I
have access to. The point is that the ANSI C standard is of no help to
me in this endeavour.
I'm sure someone here would be happy to help you with that.

What do you mean by "here"? From what I've seen of the posting in this
newsgroup in the past 10 years, there is nobody who posts here who is
capable of debugging this besides myself. But perhaps you are at a
university where you are typing this now? Don't worry, if it comes to
that I'll solicit help from people who are capable in this area, namely
sci.crypt, not in comp.lang.c.
Then either at least one of the compilers is nonconforming or you are
mistaken about the code being compliant.

Don't you get it? Writing implementation specific code doesn't make
code non-compliant in the C world.
 
W

websnarf

Flash said:
utility.)

Strange that when I ported a *complex* application to run under Cygwin
it required minimal effort.

What did you port from? If it was gcc, I will laugh my ass off. There
is more effort in porting from Intel C++ to MSVC++ (a pair of compilers
that target the identical environments, use the exact same .LIB and .H
files, and are assumed be running on the same system with access to
each other) than there is in porting from any pair of gccs.
 
K

Keith Thompson

Besides you are missing the point. I've gone to quite a bit of trouble
to make this code portable. I had high hopes that after a couple ports
everything else would just click and I'd be done. But every platform
and every compiler has presented a unique problem. For example do you
know what the following does: double d = (double)1844674407370955161ULL
? Hint: Its not just a "slight" precision loss.

I'm afraid I'll need a more explicit hint. The following:

#include <stdio.h>
int main(void)
{
double d = (double)1844674407370955161ULL;
printf("d = %.64g\n", d);
printf("expected 1844674407370955161\n");
return 0;
}

gives me this:

d = 1844674407370955264
expected 1844674407370955161

when I compile it with "gcc -std=c99".

[...]
3. In dbinc/lock.h we can plainly see that DB_LOCK_MAXID is just
defined to 0x7fffffff in the raw. Other examples of this nonsense
include DB_LOCK_DOALL, DB_LOCK_FREE, etc -- they didn't even have the
good sense to put "UL" on the end of these constants. You think they
plan on porting this to a 16 bit compiler any time soon? dbinc/mutex.h
is filled with nothing but inline assembly (and there is no coverage
for 16 bit DOS compilers, or Win 3.1 or Mac OS 9)

Why is 0x7fffffff a problem? On a system with 16-bit int and 32-bit
long (2's-complement, no padding bits), it will be of type unsigned
long. On a system with 32-bit int, it's of type int. Are there
contexts in which this will cause problems? Sure, if they're intended
to be used as unsigned longs, a "UL" suffix wouldn't be a bad idea; I
don't know the context well enough to decide whether it's necessary.
 
O

Old Wolf

Besides you are missing the point. I've gone to quite a bit of trouble
to make this code portable. I had high hopes that after a couple ports
everything else would just click and I'd be done. But every platform
and every compiler has presented a unique problem. For example do you
know what the following does: double d = (double)1844674407370955161ULL
? Hint: Its not just a "slight" precision loss.

If that value can be represented exactly by a double, then
it will; otherwise the behaviour is undefined.
 
K

Keith Thompson

Old Wolf said:
If that value can be represented exactly by a double, then
it will; otherwise the behaviour is undefined.

No, if it's within the range of double it's converted to either the
nearest lower or nearest upper representable value. It's only
undefined behavior if it's outside the range altogether, which can't
be the case for 1844674407370955161ULL.

I still don't see anything more than a "slight" precision loss (unless
you're using a compiler that doesn't support he "ULL" suffix).
 
J

James McIninch

<posted & mailed>

There was little C portability early on, but today, so long as you aren't
using Microsoft products, C is probably the most portable language around.

Most compilers (save Microsofts) adhere very well. I generally have no
problem coding up HMM algorithms in C and having it compile and run on
anything.
 
A

Allin Cottrell

James said:
There was little C portability early on, but today, so long as you aren't
using Microsoft products, C is probably the most portable language around.

As regards Microsoft, it depends. If you are writing/building software
on Windows, you are likely to be led into making non-portable
assumptions, true. But on the other hand MS does support standard C.
It's actually a nice surprise: if you write software in C on, say,
Linux, and adhere as far as possible to standard C, you'll find that
"porting" the software to Windows is trivial, if not a no-op.

Allin Cottrell
 
R

Randy Howard

As regards Microsoft, it depends. If you are writing/building software
on Windows, you are likely to be led into making non-portable
assumptions, true.

Well, as on any platform, if you ask for "interesting information",
I.e. the kind of data that is never available in standard C, then
yes, you may see yourself including a lot of headers that don't
exist elsewhere. However, this is also true on UNIX/Linux platforms,
But on the other hand MS does support standard C.

Up to C89/90 anyway. C99 from MS? Don't hold your breath.
Fortunately, that doesn't matter in practice. People writing
portable C don't use C99 features anyway, unless they provide their
own wrappers to make it work on pre-C99 compilers as well.
It's actually a nice surprise: if you write software in C on, say,
Linux, and adhere as far as possible to standard C, you'll find that
"porting" the software to Windows is trivial, if not a no-op.

Sure. That's true from any "platform A to platform B" transition,
as long as you stay inside the box. The problem is that not a
large percentage of useful software can stay purely within that
constraint. How you decide to use platform extensions when needed
can make a huge difference in the difficulty of the porting effort(s)
though.
 
A

Allin Cottrell

Randy said:
Well, as on any platform, if you ask for "interesting information",
I.e. the kind of data that is never available in standard C, then
yes, you may see yourself including a lot of headers that don't
exist elsewhere. However, this is also true on UNIX/Linux platforms,
where #include <unistd.h> seems to be boilerplate for "All the
world's a UNIX", and will get you into trouble going the other way.

Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.
Up to C89/90 anyway. C99 from MS? Don't hold your breath.

Holding one's breath on this matter would be a big mistake,
regardless of the vendor. By "standard C" I meant the de
facto standard, C89/90, not the unrealized de jure standard.
Sure. That's true from any "platform A to platform B" transition,
as long as you stay inside the box....

That's my point: 'any "platform A to platform B" transition' includes
MS Windows as the 'B', in apparent contrast to James McIninch's view.

Allin Cottrell
 
I

infobahn

Allin said:
Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.

http://tinyurl.com/3m424 (MSDN page on compatibility)

Also, every[1] C function listed in MSDN has a compatibility section
which gives clear information on the matter.

There are lots of reasons to bash MS. This isn't one of them.


[1] No, of course I didn't. Would you have done? I just looked at
one, actually.
 
R

Randy Howard

Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.

I suppose it depends on whether you take the Linux man page's word
over the ISO standard document. Otherwise, it's irrelevant. Plus,
there are numerous errors in man pages (or logical equivalent) on
just about any platform. I also seem to recall a lot of indicators
in the Microsoft docs if a function was "ANSI" or not. I don't think
they reference ISO, but I won't claim it for sure. They do have a
bad habit of not indicating what header file functions are declared
in, but that's just another doc issue.

If you are going to claim that C portability is affected by the
quality of platform man pages, I think you could come up with a
better argument, surely. :)
 
M

Mark McIntyre

Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.

At least as far as MS's documentation is concerned, thats not entirely
correct - the MSDN does state compatability for each function relatively
clearly.
 
A

Allin Cottrell

infobahn said:
Allin said:
Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.


http://tinyurl.com/3m424 (MSDN page on compatibility)

Also, every[1] C function listed in MSDN has a compatibility section
which gives clear information on the matter.

There are lots of reasons to bash MS. This isn't one of them.


[1] No, of course I didn't. Would you have done? I just looked at
one, actually.

A coupla quotes From MSDN:

<quote>

malloc

Allocates memory blocks.

void *malloc( size_t size );
Routine Required Header Compatibility
malloc <stdlib.h> and <malloc.h> ANSI, Win 95, Win NT
^^^^^^^^

</quote>

<quote>

double sin( double x );

[snip]

Example

/* SINCOS.C: This program displays the sine, hyperbolic
* sine, cosine, and hyperbolic cosine of pi / 2.
*/

#include <math.h>
#include <stdio.h>

void main( void )
{

</quote>

I rest my case.

Allin Cottrell
 
A

Allin Cottrell

infobahn said:
Allin said:
Yes, but... At least on GNU/Linux, if you consult the man page for
any given "C" function, you are given clear information on whether
it is ISO C, POSIX, BSD or something else. I think that is less
clear in the Windows world.


http://tinyurl.com/3m424 (MSDN page on compatibility)

Also, every[1] C function listed in MSDN has a compatibility section
which gives clear information on the matter.

There are lots of reasons to bash MS. This isn't one of them.


[1] No, of course I didn't. Would you have done? I just looked at
one, actually.

A coupla quotes From MSDN:

<quote>

malloc

Allocates memory blocks.

void *malloc( size_t size );
Routine Required Header Compatibility
malloc <stdlib.h> and <malloc.h> ANSI, Win 95, Win NT
^^^^^^^^

</quote>

<quote>

double sin( double x );

[snip]

Example

/* SINCOS.C: This program displays the sine, hyperbolic
* sine, cosine, and hyperbolic cosine of pi / 2.
*/

#include <math.h>
#include <stdio.h>

void main( void )
{

</quote>

I rest my case.

Allin Cottrell
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top