What's the deal with C99?

C

CBFalconer

Ian said:
There you have a problem. The C standard is cited and included
by reference in a number of other standards (C++ and POSIX for
example). So removing features from the language would have knock
on effects way beyond the C standard and existing C code.

And a correction is needed. There is a standard (ISO7185) for
Pascal, and a standard (ISO10206) for Extended Pascal. Extended
Pascal is a superset of standard Pascal.
 
I

Ioannis Vranos

Ben said:
You mean, the same way that C99 contains the sentence, "This
second edition cancels and replaces the first edition, ISO/IEC
9899:1990, as amended and corrected by ISO/IEC 9899/COR1:1994,
ISO/IEC 9899/AMD1:1995, and ISO/IEC 9899/COR2:1996."


Yes, but also making a point that C99 is obsolete, and C1x is a
descendant of C95.
 
I

Ian Collins

CBFalconer said:
And a correction is needed. There is a standard (ISO7185) for
Pascal, and a standard (ISO10206) for Extended Pascal. Extended
Pascal is a superset of standard Pascal.
By whom and to what?
 
J

Jack Klein

MS's __int64 support long predates C99, and "long long" isn't in C++
(yet).

Yes, but "long long" predates Microsoft's __int64 by quite a bit. So
much so that it is mentioned as a common extension in the informative
only Annex G of C90 (G.5.6).
And even as regards C99, it was far from clear until late in the
process if long long was going to be accepted - there was a large, and
very vocal, community that did not want long long in the standard.

Microsoft has been often maligned for breaking standards, as evidenced
by the multitude of examples in the help files for earlier compilers
containing "void main()" examples.

Frankly, I think they are overly criticized.

On the other hand, here's what the help for Visual Studio 2008 says at
http://msdn2.microsoft.com/en-us/library/6wd819wh.aspx right now:



The main function is not predefined by the compiler; rather, it must
be supplied in the program text.

<begin quote>
The declaration syntax for main is:

int main( );

or, optionally:

int main(int argc, char *argv[], char *envp[]);
<end quote>

The second example is legal as an extension in both C and C++, but
they don't mention the completely standard two-argument version. And
they don't mention that the three-argument form is an extension, and
not necessarily portable.

Following this is a section on using wmain() instead of main(), and
commendably this is very clearly marked as "Microsoft Specific".

After that, among other things, comes this:

<begin quote>
Alternately, the main and wmain functions can be declared as returning
void (no return value). If you declare main or wmain as returning
void, you cannot return an exit code to the parent process or
operating system using a return statement; to return an exit code when
main or wmain is declared as void, you must use the exit function.
<end quote>

And there is no disclaimer that defining "void main()" is undefined
behavior in C prior to C99 (and MS does not conform, nor claims to
conform to C99), and just plain ill-formed in C++.

I think Microsoft does not bother to look at existing compatibility
when defining extensions. A lot of the rest is just sloppiness on the
part of their implementers and documentation producers, coupled with
the fact that introducing portability and compatibility issues does
not bother them.

I don't know that they introduce compatibility issues deliberately as
part of an evil plan, but I don't think they worry in the slightest if
any issues that they do introduce make it difficult to port code
developed with their tools on Windows to non-Windows platforms.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
J

Jack Klein

The portions of the programming community/customer base that *weren't*
well pleased. The high-performance computing community saw some
significant barriers to optimization that they wanted to fix. The
numerical community wanted additional mathematical features. The
multinational community wanted better multilingual support. And so on.

The committee tried to determine which of the many requests would be
sufficiently useful to a large enough portion of the C programming
community to justify "forcing" every implementor to support them. I
think we did a reasonable job of that, but others will certainly
disagree. What we didn't anticipate is that there are very few vendors
whose customer base encompases all of those communities and who thus
felt compelled to implement all of C99. Instead, each vendor has
implemented just those pieces that are important to their customer base
leading to multiple de facto subsets of C99, something the committee has
always been strongly against (even the original bifurcation into
freestanding and hosted environments was hotly debated).

I am certainly glad that debate went the way it did. Since 89/90, C
has become the overwhelming language for embedded systems.

I recently saw an estimate that 75% of embedded systems use C these
days. I thought it was on embedded.com, but I can't find a link right
now. More than 25 years of embedded system work says that's probably
reasonably accurate.

Some of the high end systems are using C++ now, on 32-bit and 64-bit
platforms, but those are running OSes like Linux, WindowsCE, and
others that do provide true hosted environments.

I would estimate that some 80% of the 75% (60% or so total) of the
embedded system programming done in C is written for free standing
environments.

In fact, given the fact that C's day as a desktop application work
horse have passed, and what little visible evidence of new OS
development in C, I would draw these conclusions:

The majority of programmers making a living writing in C today, and
the majority of C code commercially produced today, are for
free-standing environments in embedded systems.

Remember, too, that OS components like kernels and device drivers,
while they may be part of a hosted environment, themselves execute in
a free-standing environment, e.g, Linux "kernel-land".

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
S

santosh

Jack Klein wrote:

I don't know that they introduce compatibility issues deliberately as
part of an evil plan, but I don't think they worry in the slightest if
any issues that they do introduce make it difficult to port code
developed with their tools on Windows to non-Windows platforms.

Some of their licenses even specify that you can use their software only
to produce programs that may run on Windows systems. Admittedly, these
are licenses for their freeware downloads, but still. I think that to
MS the idea of someone using Visual Studio to write programs that may
be ported to other systems is incomprehensible.
 
F

Flash Gordon

Malcolm McLean wrote, On 24/03/08 23:16:
You don't actually need subroutines to write even complex programs. It

<snip>

This does not disagree with what I said which is that most programmers
would consider things your basic does not provide as essential for a
serious language. I accept that at least one programmer disagrees with
this opinion. I'm sure you can also see that a program without
subroutines or procedures or functions (or whatever else you want to
call them) is not practical for a lot of programming methodologies and
so is not suitable as a general purpose language for all but exceptional
tasks.
 
I

Ioannis Vranos

Jack said:
On the other hand, here's what the help for Visual Studio 2008 says at
http://msdn2.microsoft.com/en-us/library/6wd819wh.aspx right now:



The main function is not predefined by the compiler; rather, it must
be supplied in the program text.

<begin quote>
The declaration syntax for main is:

int main( );

or, optionally:

int main(int argc, char *argv[], char *envp[]);
<end quote>

The second example is legal as an extension in both C and C++, but
they don't mention the completely standard two-argument version. And
they don't mention that the three-argument form is an extension, and
not necessarily portable.

Following this is a section on using wmain() instead of main(), and
commendably this is very clearly marked as "Microsoft Specific".

After that, among other things, comes this:

<begin quote>
Alternately, the main and wmain functions can be declared as returning
void (no return value). If you declare main or wmain as returning
void, you cannot return an exit code to the parent process or
operating system using a return statement; to return an exit code when
main or wmain is declared as void, you must use the exit function.
<end quote>

And there is no disclaimer that defining "void main()" is undefined
behavior in C prior to C99 (and MS does not conform, nor claims to
conform to C99), and just plain ill-formed in C++.

I think Microsoft does not bother to look at existing compatibility
when defining extensions. A lot of the rest is just sloppiness on the
part of their implementers and documentation producers, coupled with
the fact that introducing portability and compatibility issues does
not bother them.

I don't know that they introduce compatibility issues deliberately as
part of an evil plan, but I don't think they worry in the slightest if
any issues that they do introduce make it difficult to port code
developed with their tools on Windows to non-Windows platforms.


Yes, current C/C++ MSDN help sucks in many areas.
 
P

Philip Potter

Jack said:
And there is no disclaimer that defining "void main()" is undefined
behavior in C prior to C99 (and MS does not conform, nor claims to
conform to C99), and just plain ill-formed in C++.

void main() is undefined in C99 too.
 
L

lawrence.jones

Paul Hsieh said:
Primarily its because the standards committee has totally lost touch
with the real world of computer programming.

They did not, 1) attempt to assess the implementability of C99. They
also did not 2) assess the *value* of each feature to actual
programmers. And finally they did not 3) seek to encode features that
programmers need or want.

That is incorrect in every particular. There is *no* part of C99 that
has not been implemented. Many parts were implemented before they were
standardized. They have been implemented precisely because they *are*
of value to actual programmers who need or want them.
Well, in the case of gcc, apparently the variable length arrays are
fatal, because some critical amount of the code out there that uses
gcc relies on the specific gcc semantics which conflict with C99's
VLAs.

It's interesting to note that GCC is the only major compiler that has
never been represented in the standardization process. I consider that
a major loss for GCC, the C standard, and the C community in general.
Not only is it almost entirely useless (who the hell can't program up
their own complex numbers for crying out loud!), it conflicts with the
C++ template (namespace-wise) which does the exact same thing but is
more general (and therefore the C99 version *cannot* be taken forward
to C++).

While it's not too hard to handle simple complex arithmetic yourself,
the syntax you have to use is quite awkward, at least some of the
operations are apt to be implemented poorly (unless you're a numerical
analyst), and you end up having to implement the whole blessed math
library if you want to do actual math (as opposed to arithmetic), which
is definitely a non-trivial task.

The C solution was never intended to be taken forward -- the C++
solution is perfectly fine for C++, but it's not viable for C. The
intent was to come up with a solution for C that was "compatible" with
the C++ solution, meaning that it is possible with just a little
preprocessor magic to write code that will compile as either C or C++.

-Larry Jones

He's just jealous because I accomplish so much more than he does. -- Calvin
 
K

Keith Thompson

Philip Potter said:
void main() is undefined in C99 too.

Sort of.

C99 added (unwisely IMHO) a clause explicitly allowing the main
function to be defined "in some other implementation-defined manner"
(C99 5.1.2.2.1). (This is redundant, given the general permission to
provide extensions in C99 4p6, and the identical permission in C90.)

Note that for something to be "implementation-defined", it must be
explicitly documented.

So the behavior of "void main()" (or "void main(void)") is undefined
*unless* the implementation's documentation explicitly permits it. Of
course it's still undefined for other implementations.

There is no good reason to declare "void main()" in a program intended
for any hosted implementation.
 
P

Paul Hsieh

Paul Hsiehwrote:

[mixed code and declarations]
Oh worse than that, they are pointless in a non-C++ environment.
"Declare anywhere" is a very specific work around in C++ to allow you
control over the order that constructors are called.
By their nature they heavily degrade the readability of code. If you
see a variable and want to know what type it is, you have to scan the
code sequence leading up to its use, rather than just the declaration
blocks.

It's pretty clear that this is a matter of opinion. Some of do prefer
to introduce variables when they can be meaningfully initialised. Loop
indexes are an obvious instance.

Classic -- its the facts versus opinion argument. (Compare to climate
change, or "Intelligent Design" versus evolution.)

The side which can only support their side with opinion are those that
endorse the arbitrarily positioned declarations. Those that can cite
actual facts and real concrete problems are those that oppose
arbitrarily positioned declarations.

When you say its just a matter of *opinion*, you are implicitly
choosing a side. You need to degrade the position of those against
it, as if it were merely a matter of opinion, because you know that
your side is nothing but.
 
R

robertwessel2

On the other hand, here's what the help for Visual Studio 2008 says athttp://msdn2.microsoft.com/en-us/library/6wd819wh.aspxright now:

The main function is not predefined by the compiler; rather, it must
be supplied in the program text.

<begin quote>
The declaration syntax for main is:

        int main( );

or, optionally:

        int main(int argc, char *argv[], char *envp[]);
<end quote>

The second example is legal as an extension in both C and C++, but
they don't mention the completely standard two-argument version.  And
they don't mention that the three-argument form is an extension, and
not necessarily portable.


In MS's defense, the link to "Argument Definitions" on that page
clarifies that considerably, where they define the one, two and three
argument forms of main() as valid, and the third (envp) parameter as a
*nix and MS extension. OTOH, it's not particularly clear that only
the two argument form is actually standard. Without some reading
between the lines ("The types for argc and argv are defined by the
language" on the prior page), and some interpolation, I suspect most
readers would assume from those two pages that a single argument (argc
only) form of main() is standard too.

Yes, it could definitely be clearer...
 
F

Flash Gordon

Paul Hsieh wrote, On 25/03/08 16:38:
Paul Hsiehwrote:

[mixed code and declarations]
Oh worse than that, they are pointless in a non-C++ environment.
"Declare anywhere" is a very specific work around in C++ to allow you
control over the order that constructors are called.
By their nature they heavily degrade the readability of code. If you
see a variable and want to know what type it is, you have to scan the
code sequence leading up to its use, rather than just the declaration
blocks.
It's pretty clear that this is a matter of opinion. Some of do prefer
to introduce variables when they can be meaningfully initialised. Loop
indexes are an obvious instance.

Classic -- its the facts versus opinion argument. (Compare to climate
change, or "Intelligent Design" versus evolution.)

The side which can only support their side with opinion are those that
endorse the arbitrarily positioned declarations. Those that can cite
actual facts and real concrete problems are those that oppose
arbitrarily positioned declarations.

Well, when one side is stating their opinions as fact and the other side
is stating their opinions as facts...
When you say its just a matter of *opinion*, you are implicitly
choosing a side. You need to degrade the position of those against
it, as if it were merely a matter of opinion, because you know that
your side is nothing but.

Your concrete example of needing to search for the definition does not
apply to a lot of people. They use the tools to do the searching for them.
 
I

Ian Collins

Paul said:
Paul Hsiehwrote:

[mixed code and declarations]
Oh worse than that, they are pointless in a non-C++ environment.
"Declare anywhere" is a very specific work around in C++ to allow you
control over the order that constructors are called.
By their nature they heavily degrade the readability of code. If you
see a variable and want to know what type it is, you have to scan the
code sequence leading up to its use, rather than just the declaration
blocks.
It's pretty clear that this is a matter of opinion. Some of do prefer
to introduce variables when they can be meaningfully initialised. Loop
indexes are an obvious instance.

Classic -- its the facts versus opinion argument. (Compare to climate
change, or "Intelligent Design" versus evolution.)

The side which can only support their side with opinion are those that
endorse the arbitrarily positioned declarations. Those that can cite
actual facts and real concrete problems are those that oppose
arbitrarily positioned declarations.

When you say its just a matter of *opinion*, you are implicitly
choosing a side. You need to degrade the position of those against
it, as if it were merely a matter of opinion, because you know that
your side is nothing but.
Style is always a matter of opinion. There isn't a wrong or a right way,
the choice is purely subjective.

My opinion, shared by my colleagues, is that variables should be
declared where thy can be meaningfully initialised. I can't see how
declaring a loop counter somewhere other than where it is used aids code
readability. It might if that's the style of code you are used to
reading, but it's a pain if it isn't. The same applies to variables
used for intermediate results.

Your sig is still broken.
 
I

Ian Collins

While it's not too hard to handle simple complex arithmetic yourself,
the syntax you have to use is quite awkward, at least some of the
operations are apt to be implemented poorly (unless you're a numerical
analyst), and you end up having to implement the whole blessed math
library if you want to do actual math (as opposed to arithmetic), which
is definitely a non-trivial task.
I think C99 would have gained greater acceptance with the embedded
community if the new numerical features (including _Complex) has been in
its own numerical standard.
 
L

lawrence.jones

Ian Collins said:
I think C99 would have gained greater acceptance with the embedded
community if the new numerical features (including _Complex) has been in
its own numerical standard.

I don't know why that would have made any difference, freestanding
implementations don't have to provide complex types or most of the
standard library.

-Larry Jones

I can feel my brain beginning to atrophy already. -- Calvin
 
P

Philip Potter

Keith said:
Sort of.

C99 added (unwisely IMHO) a clause explicitly allowing the main
function to be defined "in some other implementation-defined manner"
(C99 5.1.2.2.1). (This is redundant, given the general permission to
provide extensions in C99 4p6, and the identical permission in C90.)
Agreed.

Note that for something to be "implementation-defined", it must be
explicitly documented.

So the behavior of "void main()" (or "void main(void)") is undefined
*unless* the implementation's documentation explicitly permits it. Of
course it's still undefined for other implementations.

How does that differ from undefined behaviour? fflush(stdin); is
undefined unless an implementation's documentation explicitly permits
it. The only difference is that the Standard doesn't implicitly state
that an implementation might document some behaviour for fflush(stdin);.
But such statements from the Standard are hardly useful.

This particular implementation-defined behaviour is odd because
a) it doesn't require an implementation to document when it doesn't
support void main();, and
b) it doesn't require an implementation to document when it does support
void main(); either!
Why? Because if an implementation doesn't document that it supports void
main();, then a program which declares main as void invokes undefined
behaviour, and the implementation is freed from all requirements placed
on it by the standard, and is perfectly free to accept the program!

I'm pretty sure that the C90 wording could have been used (void main()
is undefined, full stop) and this would not affect the behaviour of any
program or the conformance of any implementation.

If it looks like a duck, and it quacks like a duck...

[I have thought of one possible exception to the above: an
implementation which claimed to support void main() but actually didn't
might be conforming under the C90 wording but nonconforming under C99.
IOW, by specifying that main() might be declared in some
implementation-defined manner, the Standard requires the implementation
to stick to its promises. I'm not entirely sure this line of reasoning
is correct or even sane...]
There is no good reason to declare "void main()" in a program intended
for any hosted implementation.

Agreed.
 
P

Paul Hsieh

That is incorrect in every particular.

Nonsense. You don't substantiate even *one* counter-claim.
[...] There is *no* part of C99 that
has not been implemented. Many parts were implemented before they were
standardized.

*Sigh*. *OBVIOUSLY*. But that's a ridiculously low bar.

They had to make sure that the whole she-bang could be all done at
once. But its obvious from looking at the Intel effort and the gcc
effort (both groups, being *motivated* to implement C99) that
something stopped each of them. In the end you end up with just a
couple of marginal C99 implementations which can only do so because
they are so marginal that they don't have any backward compatibility
problems to deal with.
[...] They have been implemented precisely because they *are*
of value to actual programmers who need or want them.

You have to be kidding me. Complex numbers that are incompatible with
C++?!?! Randomly positioned declarations? This is nonsense that
special interest groups may have asked for -- but do you see any of
these same people demanding C99 compilers being implemented do you?

If you want to know what programmers want, you have to test it against
the directions that programmers have *actually gravitated* to. This
testimony is to be found from two main directions: 1) modern CPU
capabilities that are used and yet are non-encodable by the language
and 2) ideas from modern languages like Java, Python, Perl and so on.
It's interesting to note that GCC is the only major compiler that has
never been represented in the standardization process. I consider that
a major loss for GCC, the C standard, and the C community in general.

I agree. So what the hell is the committee planning on doing about
it? If you look through the mailing lists for gcc, you will find that
many vendors talk to them and influence them all of the time (I am
specifically thinking of WindRiver and AMD).
While it's not too hard to handle simple complex arithmetic yourself,
the syntax you have to use is quite awkward, at least some of the
operations are apt to be implemented poorly (unless you're a numerical
analyst), and you end up having to implement the whole blessed math
library if you want to do actual math (as opposed to arithmetic), which
is definitely a non-trivial task.

What? First of all, if you need to *deal* with complex numbers in a
non-trivial manner (like implementing trigonometry, or numerical
integration or something like that), you better *BE* good enough to
implement your own complex number library.
The C solution was never intended to be taken forward -- the C++
solution is perfectly fine for C++, but it's not viable for C.

And you are saying the embedded/driver applications have a great need
for really marginal and difficult to implement complex numbers?

C++ is the *path* to take C forward. It means that the areas that
they carve out should be solved by them, and the C standard committee
should accept this fact. This is the only, and best way for them to
remain relevant. This lack of consideration for C++ has help *cause*
C99 to be ignored by end-users.
[...] The
intent was to come up with a solution for C that was "compatible" with
the C++ solution, meaning that it is possible with just a little
preprocessor magic to write code that will compile as either C or C++.

And if you want to do number theory on guassian integers, is it still
just a matter of preprocessor tricks?

Why do you think anyone cares about problems already solved in C++
being solved yet again in C (which is now most commonly available as
just another mode of C++ compiler)?

Look. C is a malloc/free based language. Every new language has
implemented garbage collection as a means of escaping the weaknesses
of the C model. This is one of the most glaringly obvious issue with
C. Now, I don't think C needs to *SWITCH* to GC. Instead, this
outlines the need to do *BETTER* with the malloc/free model, as a
*COUNTER* to those that are running away from it because of its
weaknesses. Also we see from things like Electric Fence, Purify,
Visual C++'s memory debugging facilities, that there is both a need
and demonstrated ways of improved memory managing. This is obvious,
and all this information has been around forever. So who in the
standards committee has looked into improved memory management for
C99?

Many CPUs have bit scan, bit count, and widening multiply
instructions. All of these functions can be emulated very slowly but
portably but cannot reasonably be mapped to the fast hardware via "as-
if" rules. They also all have practical applications in the real
world. If the C standard committee merely added APIs for these into
the standard library, it would open a vast unmatchable performance
wedge against all other languages (including C++, until they added
them to their standard as well.) So which of these functions were
added, or proposed to be added to the C99 standard?

Every database-like program that implements ACID, does so with a very
twisted sort of file management. People who used CVS heavily during
the mid to late 90s knows exactly what the problem with this is (CVS
was unsound due to bad file locking implementations for much of its
lifetime). Different file systems have different characteristics and
guaranteeing atomicity is done on a case by case basis. If there was
an API for some atomic file primitives in the C standard, this could
force OSes to expose a unified API which would in turn force the disk
drive manufacturers to provide some kinds of guarantees about their
product. What did the ANSI C committee say about this?

Just think about those things for a second. If C99 had implemented
any of those, don't you think that there would at least be *SOME* buy
in from end users?

And that ignores what the C standard committee *should* do just for
sanity reasons (fix the ftell/fseek nonsense, fix the time APIs to be
non-static and >= 64 bits).
 
W

Walter Banks

Ian said:
I think C99 would have gained greater acceptance with the embedded
community if the new numerical features (including _Complex) has been in
its own numerical standard.

This part of the ongoing WG14 debate. After C99 was released
WG14 released a TR ISO/IEC18037 that added fixed point data types
to the C language at this point it is still a technical report. 18037 is
specifically of interest to embedded systems. There are other TR's
that also have a market segment niche.

There has been a lot of debate about how the C standard should be
structured. A core of language elements and perhaps support for
market segments. There is no general consensus what approach
should be taken.

This is going to get even more complex as C support evolves for
specialized processor architectures. We have written one compiler
for a thread based embedded processor that cannot call main for
example. (no code is executed on reset)


Regards,
 

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

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top