C, really portable?

R

Richard Heathfield

jacob navia said:
Is a program just using printf portable?
The result of printf is negative if there was an error,
but the exact values are implementation specific and
will change from this implementation of printf to the
next one. This makes impossible any error analysis
of that function call in a portable way.

There are several reasons printf can fail. These reasons are not themselves
portable. On one system, it might be possible for printf to fail because a
disk has filled. On another system, printf might only ever fail if someone
forgot to feed the goat. When you bear in mind that systems yet to be
invented will have failure modes yet to be imagined ("Ae'm sarry capt'n,
but the neutrino laser's peptide tube has melted again, and it's messing up
all mae printfs"), it becomes clear that /no/ language can provide portable
error analysis.

C cannot make inherently non-portable concepts /become/ portable. Where it
scores highly is in retaining the portability that does already exist
within a problem. For example, it is known that printf can fail, albeit for
a variety of reasons. The /reasons/ are not portable, but the concepts of
success and failure /are/ portable, and C rightly lets us distinguish
between them.
 
N

Nathan Wagner

[snip]
The only thing the standard could be taken to task for is that it does not
require that printf() update errno on encountering an error. It does not
disallow this either, but it needlessly complicates error recovery in
response to printf() calls even where we do know what could go wrong.

While I agree that the standard could perhaps be better in this regard,
if you really were planning on using errno for this, it would be
easy to provide a

*pseudocode*
int do_printf(...) {
int r;
r = printf(...);
if (r<0) errno = 1;
return r;
}

A pain I suppose, but so is manual memory management. If you want
C++/Perl/Pascal/Lisp/Prolog/Java/Haskell/Ada you know where to get them.

It would be nice though if all errors were either inline or via errno.
 
N

Nathan Wagner

I wouldn't mind seeing some kind of exception handling mechanism in a future
C standard, though not one as elaborate as what C++ has.

Doesn't C have this already via longjmp()? It's basic and simple.

Is longjmp() used for anything other than error/exception handling?
 
N

Netocrat

]
I'd still rather test for errno!=0 than errno>0. If errno *is*
somehow set to a negative value, it probably indicates an error (in
the code that sets errno if nothing else).

Agreed (2nd sentence) - that's why the code prints "fprintf: unspecified
error" for negative errno's.

All the Standard specifies is that perror "maps the error number ... to an
appropriate error message string". The "appropriate" mapping for a
negative errno may be something like "unspecified error" anyhow, but OTOH
it may be "invalid negative error code".

OK, just realised I can check this... with gcc and glibc for errno of -1,
perror's mapping is "Unknown error 4294967295".

Eric Sosman raised the issue of confusing messages. I find "unspecified
error" more helpful than "Unknown error 4294967295", especially
considering that fprintf wouldn't have intended "4294967295" (really -1)
to have been interpreted as an error code.
 
E

Eric Sosman

Nathan said:
Doesn't C have this already via longjmp()? It's basic and simple.

Basic and simple, yes. The problem is that its
simplicity makes it hard to use. Consider a function
a() that calls setjmp() and then invokes b(). b()
allocates some memory, opens a file, loads data from
the file into the allocated memory, and calls c() to
operate on the memory. Depending on the value returned
by c(), b() either loads the next batch of data and calls
c() again or else closes the file, frees the memory, and
returns to a().

Unfortunately, c() calls longjmp() and skips straight
back to a() without giving b() a chance to clean up. The
memory remains allocated and the file remains open, and
since this is contrary to the expected behavior of a b()
call there may well be trouble. That's the principal
drawback: longjmp() leaps from a point deep in the call
stack straight back to the setjmp() caller, and doesn't
give the intervening functions any chance to put their
affairs in order.

Now, it is certainly possible to build a more elaborate
mechanism atop basic and simple longjmp(). One can also
exercise ferocious discipline to avoid writing a b() that
calls a possibly-longjmp()ing c() while still in a state
that requires cleanup. Both approaches require extra work
since the language itself offers no help; both approaches
are viable but not as basic and simple as longjmp() itself.
Is longjmp() used for anything other than error/exception handling?

Various people have tried to build a kind of coroutine
linkage out of it, but I haven't yet seen one that looked
much good: They all seem to involve longjmp()ing back into
a function that has already returned, perhaps by a longjmp()
of its own. Cooperative multi-threading schemes appear to
rely on the same sort of abuse. (I have not, of course, seen
everything.)
 
P

P.J. Plauger

I think it is both. It is a much better OO language than C++, since the
designers learnt from the mistakes.
A big advantage over C is that you have automatic memory allocation. No
more messing about with testing mallocs() and then painstaking freeing
your half-built structure on fail, just for a refusal to give you a
hundred bytes that can never happen.
A big disadvantage in relation to C is the automatic memory allocation -
now we can't fine tune the prgoram where we need performance.

I pretty much agree with that assessment.
All practical C programs use pointers. Most Java programs don't need
threads.

Right. And pointers work right, if you use them right -- even near
and far ones. Whereas Java threads often *appear* to work right,
when you use them right, on one platform then behave pathologically
on another platform. They've even been known to change behavior
between releases of one OS. IMO they're two entirely different
kettles of fish.
What I have never done is written an all-singing, all-dancing Java
interactive application. I just use it for providing a simple graphical
UI. I would prefer C, but there is no standard windowing library that all
platforms (with appropriate hardware) are guaranteed to support.

Again, I agree that's a good use for Java instead of C.
This would be a trivial job - just define half a dozen function to open a
window, close it, draw a pixel, query the mouse position, and synchronise
the screen. However no-one has done so, and it is non-trival to implement
such an interface given another a high-level interface.

I've seen several implementations of just such an interface,
callable from C. The problem is that you need another layer or
two atop this set of primitives to get anything done. And IMO
this is still an experiment in process. I've played a bit with
X, Qt, and the first couple of generations of Java. (The fact
that Java is on its third or fourth GUI tells you something
about the state of the art.) All of these are find for drawing
simple screens, but all show surprising variations in screen
appearance across different platforms.

Yes, I kinda wish Standard C came with at least a simple
graphics package. I'd use it to produce simple graphic
displays. But I'm not sorry that the C and C++ standards
committees have shied away from this area -- both have plenty
of work to do with a more certain payoff.
It depends what you are doing, Java aims for rigorous portability - the
same program produces the same output, regardless of platform. Obviously,
we would chose this, other things being equal.
C aims for the next level of portability - the same program produces
correct output, regardless of platform.
So let's say my task is to load in a model of a molecule, rotate it given
user angles, and then output the result as a JPEG image. If the patron
specifies that the JPEG file must be, byte for byte, exactly the same on
every platform, then Java is the language to go for. There might be good
reasons for demanding this - for instance, you can test the program
automatically. Normally, however, the patron is happy with an image that
he can view, and shows the molecule in the orientation he entered.

I mostly agree with your representation of the goals of Java and C.
I don't agree with the degree to which Java has succeeded or C
has failed, at least in the context of your example.
But this is an unacceptable situation, which we must work to change.

You may find it unacceptable, but I don't expect it to change
in (what's left of) my lifetime. That's just good engineering
practice. We can work to lower the *cost* of testing, but test
we must.
An
engineer working for a bolt factory expects to have to test his bolts for
stress, manufacturing tolerances, or whatever. The engineer building a
bridge expects to order the bolts, and for them to do what it says on the
box. That's the way it should be with software.

And it is, to the extent that the behavior of software in
a large system has no greater impact than, say, a failing
bolt, it's testing is separable and isolated.
I think a common mistake is to suppose that the main benefit in writing
portbale code is to be able to compile and run it on a different platform.
It sounds commonsensical. In fact, by making code portable, you improve
the logical structure of your program, making it more readable, and less
likely to contain errors. That is often a much greater benefit.

Sometimes that's true. Sometimes you have to expend extra
effort, as I said above. I agree that the *habits* that
help you write portable code also benefit non-portable
code. I like to believe that's what you meant.
I don't know about that one. I use Java for trivial GUI apps, precisely
because C has no library. I would prefer to keep all my code in the same
language.

Again I agree. But I can assure you that, as both a consumer
and producer of standard libraries, bigger is *not* necessarily
better. IME, it's almost always worse.
With most of these things, you have to choose between them and pointers.
It is easy enough to serialise a data structure, as long as it has no
pointers. It is a bit harder to provide threading, but a lot harder still
if you cannot protect memory. Same for arrays and memory leaks.
C is the language of pointers.

Yes it is, and I don't take that as axiomatically bad/dangerous/
inconvenient/whatever as you seem to. C++ has references, which
are effectively secret, read-only, guaranteed initialized
pointers; but you can subvert them too and cause really hard
bugs to find. Java and other OO languages have handles, which
are even more tightly managed than references, but they too
have their problems -- memory leaks, uncertain object lifetimes,
etc. Eliminating pointers is neither necessary nor sufficient
to improving code reliability IMO/IME.
How do you know you are not suffering from a mental illness?

<OT>Good point. You will notice that I distinguish my internal
reality from the real world -- that's an important self check.
But even if I'm a four-door nutcase, I *still* know more about
what's inside my head than others, who have to use indirect
means. And I deeply resent anybody telling me what I think
or feel, particularly someone with a weak grip on logic and
fuzzy boundaries between different views of reality. said:
I'm using Fortran 77. When I started my new position, everyone was using
it, because it was the standard for academic programming. I decided to put
IO and memory allocation into C, and keep the numerical part of the
program in Fortran - I think it was the right decision but two months into
starting, all we've really achieved is to convert existing assets from
Fortran 77 to C, so I won't now do the scientific work I had hoped to do
by Christmas.
I'm working now, in December 2005. So for me Fortran 77 is very much still
a modern language.

Indeed it is. Otherwise, C and C++ wouldn't keep working so hard
to lure Fortran programmers.
Sure. I'd say that a very important rule is "will this program be usable
if compiled with zero changes to the source?". Even if you need to make a
trivial change, e.g. converting MAX_PATH to _MAX_PATH, you require a
competent programmer, and the value of the source is diminished.
However even this isn't completely Boolean. What about source which
compiles, but on Unix require an "-lm" to be added to the the makefile /
compiler options? This is a similar irritation, but not as bad as the
source change. In a lot of environments, the rule will be "OK, the source
has changed, now please rerun all the test suites", but not if a compiler
flag changes.

You're describing various implicit costs in moving even a
"completely portable" program to another platform. That's
why the dictionary definition is so lame -- it describes
a Platonic ideal with next to no practical significance.
When I use Perl, I usally use it for tasks that are not portable, because
it ships as source and hacking into a perl script is less intimidating
than recompiling C source. So if you want to load a thousand models from
/freddy/models, all starting with "att" and with digits between 0-52 as
suffixes, Perl is ideal. The task is, of course, very much dependent on
the needs of the moment.

Exactly. Our little shop does an incredible amount of in-house
work with "scripts" in: DOS command, Unix sh, ed, awk, perl,
Visual Basic, Maplesoft, and doubtless several other things
that Chris, Pete, or John has seen fit not to let me find out
about. Our goal is to produce highly portable and reliable:
C, C++, HTML, DOS scripts, and sh scripts. But we try to be
clear, for each of the bits of code we produce, just how
portable/readable/tested it should be.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
K

Keith Thompson

Netocrat said:
]
I'd still rather test for errno!=0 than errno>0. If errno *is*
somehow set to a negative value, it probably indicates an error (in
the code that sets errno if nothing else).

Agreed (2nd sentence) - that's why the code prints "fprintf: unspecified
error" for negative errno's.
[...]

One of these days, I just might consider reading code before
commenting on it. (*sigh*)
 
M

Mark McIntyre

I assume that if fprintf returns a negative value the disk
is full.

Well, I suspect you could be less assumptive than that

if (fprintf(fp, "foo")< 0)
{
puts("unable to write foo");
puts("possible causes: disk full, disk offline, tape removed");
puts("ion storm near mercury, no more memory etc");
puts("or a suitable list of sensibile possibilities given");
puts("the type of device you're trying to write to"):
puts("Yu decide");
exit(1);
}
switch (err) {
case EOF:
// No space. Erase temp files
break;
default:
// Other errors
}
return err;

The problem I have with this is that there's typically no actual
action the programme can take. There may /be/ no temp files, there may
not be a disk, the "no space" error might arise because the
destination really meant "I'm busy, go away and come back in 5"...

Plus that sort of error handling is deeply icky.
 
M

Mark McIntyre

Please go use VMS for several years. It *does* this. Once you
have experience with how it works (and when and how it fails),
*then* come back and propose putting it into a future C standard.

Gawd how I miss those VMS error codes. It certainly teaches one to
return sensible values from main()...
 
C

Chris Hills

pemo said:
Is C really portable?

No. The standard embodies a portable syntax which exists as subset of
any compliant compiler, but that's exactly as meaningless as you might
suspect it is. For example, I don't believe there exists any pair of C
compilers from different vendors that have exact source space
compatibility.
[...] And, apologies, but this is possibly a little OT?

Well C.L.C. is a group about ANSI standard C.

No. It is about ISO C
 
K

Keith Thompson

Chris Hills said:
pemo said:
Is C really portable?

No. The standard embodies a portable syntax which exists as subset of
any compliant compiler, but that's exactly as meaningless as you might
suspect it is. For example, I don't believe there exists any pair of C
compilers from different vendors that have exact source space
compatibility.
[...] And, apologies, but this is possibly a little OT?

Well C.L.C. is a group about ANSI standard C.

No. It is about ISO C

I might have written "Yes. it is about ISO C".

As everyone here probably knows by now, the original C standard was
issued by ANSI in 1989. ISO adopted it (with some changes like
renumbering the sections) in 1990; ANSI, as the US member of ISO,
adopted the ISO standard. The current standard is the 1999 ISO
standard, which is also recognized by ANSI. (And there have been a
couple of technical corrigenda since then.) I suppose it's debatable
whether C99 can properly be referred to as "ANSI C", but it's not
interestingly debatable.

The term "ANSI C" is used colloquially to refer to the 1989 standard
(the term became popular while the standard was still being developed,
and it stuck). Discussion of the language defined by the 1989 ANSI C
standard is topical here. So, I would say, is discussion of the
pre-ANSI version of the language defined by K&R1, and even earlier
versions from before that.

IMHO, YMMV, HAND.
 
R

Robert Gamble

Chris said:
pemo said:
Is C really portable?

No. The standard embodies a portable syntax which exists as subset of
any compliant compiler, but that's exactly as meaningless as you might
suspect it is. For example, I don't believe there exists any pair of C
compilers from different vendors that have exact source space
compatibility.
[...] And, apologies, but this is possibly a little OT?

Well C.L.C. is a group about ANSI standard C.

No. It is about ISO C

What is that supposed to mean? Are you saying that only the latest
version of C is topical here or that neither verion of the Standard is
correctly referred to as ANSI C? The original standard was created by
ANSI and adopted by ISO, the latest verion was created by ISO and
adopted by ANSI so I don't see your point if that was your argument.

Robert Gamble
 

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
474,172
Messages
2,570,934
Members
47,474
Latest member
AntoniaDea

Latest Threads

Top