Is C99 the final C?

A

Arthur J. O'Dwyer

const int foo = 5;
char arr[foo];

Legal C++ (because in C++, const objects are really "constant"),
but illegal C (because 'foo' is an object whose value needn't
be stored [or even computed] at compile time). I think C's way
is easier for me to grasp. And I think (but this is just IMH
and uneducated O) that C++ compilers need a lot of extra baggage
to deal with constant "consts," and I wouldn't want to foist all
that on C compilers.


Something like

fancy_enum { fred=32, george=23 } bar;
bar = fred;
bar++; /* bar now equals george */

possibly?

Ooh, that would just be ugly and mean. ;)

i=0;
while (1) {
/* do stuff */
if (i==INT_MAX) break; /* or whatever other MAX */
i++;
}

Even uglier but safe for signed types.

Except possibly for flavors of 'char', why would anyone want to
walk over all values of a type anyway? Solving equations by
exhaustive search? ;-)

-Arthur
 
S

Simon Biber

Arthur J. O'Dwyer said:
I suppose that would be possible -- but it would be ugly and
inefficient, and might have odd interactions with 'volatile'.
Plus, you'd need to generate code and/or space for a "staging
area" for all these misaligned values (the targets of all these
memcpy's), and that would probably make things a little more
complicated for the linker -- which object file gets the "staging
area" and which just refer to it? or does each TU get a separate
staging area, which would be inefficient?
I just don't like it. :)

I don't like it either, but it would be nice to have a well-defined
way to get packed structs on any implementation. Obviously, because
of the large performance hit, you would only use the packed attribute
where it was absolutely necessary.
If a is non-zero, return b; else if a is zero, return a.
If a is non-zero, return b; else if a is zero, return 0.
Means the same thing, and my way doesn't have to evaluate
a two times, so it's macro-safe.

Of course, sorry.
Ditto the above comment about macro-safety, although
I guess my way does evaluate 'result' twice. Bottom
line -- use whichever way makes the code do what you
want it to do. :) I don't think there's any need for
new operators here.

Your way is unsuitable for macro use anyway -- there is
no result object in an expression-like macro.
Oh, and just for kicks, note that the &&& operator
would break some [pathological] C code.

Like this:
int a = 1, b, *p = &b;
if(a != 0 &&& b == p)
{
printf("a is non-zero and the address of b is equal to p\n");
}
 
S

Sidney Cadot

Mark said:
Definitely not. CHAR_BIT==9 may be rare these days, but CHAR_BIT==16 is
not once you start looking at DSP processors which often don't have the
ability to access less that 16 bits (or or) in one operation.

Ok. Good point.
Requiring a diagnostic (not necessarily an error) for using unprototyped
functions might be of help.

Yes, that would be a seriously good idea for a proposed change.
Something like

fancy_enum { fred=32, george=23 } bar;
bar = fred;
bar++; /* bar nor equals george */

possibly?

I think this was not the intended meaning of the statement. However,
this raises an important question. For backward compatibility, it is
inevitable that (int)bar would equal 33 after the post-increment, I think.
<snip>

i=0;
while (1) {
/* do stuff */
if (i==INT_MAX) break; /* or whatever other MAX */
i++;
}

Even uglier but safe for signed types.

Ok. I'm not sure if I can think of a better way, so let's keep it like
it is :)

Best regards, Sidney
 
S

Sidney Cadot

Arthur said:
const int foo = 5;
char arr[foo];

Legal C++ (because in C++, const objects are really "constant"),
but illegal C (because 'foo' is an object whose value needn't
be stored [or even computed] at compile time).

This is legal at least in C99, and I think also in C89 (at least my gcc
doesn't even warn on it).
I think C's way
is easier for me to grasp. And I think (but this is just IMH
and uneducated O) that C++ compilers need a lot of extra baggage
to deal with constant "consts," and I wouldn't want to foist all
that on C compilers.

Given that it already works, this would be a moot point.
Except possibly for flavors of 'char', why would anyone want to
walk over all values of a type anyway? Solving equations by
exhaustive search? ;-)

That's a nice example ...

Best regards,

Sidney
 
S

Sidney Cadot

Simon said:
Oh, and just for kicks, note that the &&& operator
would break some [pathological] C code.


Like this:
int a = 1, b, *p = &b;
if(a != 0 &&& b == p)
{
printf("a is non-zero and the address of b is equal to p\n");
}

True, but at least this wouldn't go unnoticed under hypothetical &&&
semantics, given that the expression "b==p" isn't valid.

Best regards, Sidney
 
I

Irrwahn Grausewitz

Sidney Cadot said:
Arthur said:
The last statement I do not understand. Care to elaborate?

const int foo = 5;
char arr[foo];

Legal C++ (because in C++, const objects are really "constant"),
but illegal C (because 'foo' is an object whose value needn't
be stored [or even computed] at compile time).

This is legal at least in C99, and I think also in C89 (at least my gcc
doesn't even warn on it).

It's not legal in C89. You didn't invoke gcc with the appropriate
set of options. ;-) You should get a

warning: ISO C89 forbids variable-size array `arr'

In C99 it should work, given that the variable length array 'arr' is
declared inside a function; otherwise you should get something like:

variable-size type declared outside of any function
Given that it already works, this would be a moot point.

But it doesn't work. :) 'const' qualified variables in C are not
compile-time constants. This is one of the important points
where C++ differs.

<snip>

Regards
 
S

Sidney Cadot

Irrwahn said:
Sidney Cadot said:
Arthur J. O'Dwyer wrote:

The last statement I do not understand. Care to elaborate?

const int foo = 5;
char arr[foo];

Legal C++ (because in C++, const objects are really "constant"),
but illegal C (because 'foo' is an object whose value needn't
be stored [or even computed] at compile time).

This is legal at least in C99, and I think also in C89 (at least my gcc
doesn't even warn on it).


It's not legal in C89. You didn't invoke gcc with the appropriate
set of options. ;-) You should get a
warning: ISO C89 forbids variable-size array `arr'

You're right. I forgot the -pedantic ... Silly gcc folks ... Stupid me ...
In C99 it should work, given that the variable length array 'arr' is
declared inside a function; otherwise you should get something like:

variable-size type declared outside of any function
Check.

Ok, it's not a moot point, then.
But it doesn't work. :) 'const' qualified variables in C are not
compile-time constants. This is one of the important points
where C++ differs.

Okidoki. That's what I _thought_ until I tried and made a silly mistake.
Sigh.

Regards,

Sidney
 
M

Mark Gordon

I think this was not the intended meaning of the statement. However,
this raises an important question. For backward compatibility, it is
inevitable that (int)bar would equal 33 after the post-increment, I
think.

That was why I suggested something other than enum. I'm not sure what
else the person who said he wanted enums to be more special might have
meant.
Ok. I'm not sure if I can think of a better way, so let's keep it like
it is :)

I must admit that a simpler solution might be nice, but it would require
a new control structure.
 
M

Malcolm

Jack Klein said:
Can you provide a sample implementation to show how it would
work?
The easiest option would be to use C++ syntax, and run the code through a
C++ compiler if no C 2003 compiler is available, maybe with a simple front
end to check the code complies.
I could wish that pigs had wings so they could fly, but unless I can
come up with at least some solid engineering plans that showed
feasibility and a favorable cost-benefit ration, I would not expect
anyone to take my wish seriously.
I think there are two to be made for templates. The weak case is that often
it is handy to write a function once with several types of arguments. For
instance swap() naturally lends itself to a template implementation. So too
does mean().
Personally I don't think these cases are common enough to justify a new
language feature, and also involve some subtle problems. For instance mean()
is fine for floats and doubles, but will usually break when fed a char
array, and could easily break with a short.

The stronger case is that the C++ standard template library allows client
code to do away with dynamic memory, and almost to do away with pointers.
These are probably the two features of C which cause more bugs than any
other, and also doing away with them would allow safe applications, for
instance in programs to be distributed over the net. This may be an
advantage. The problem is that the new language would no longer be
recognisably C.
 
J

James Kuyper

Sidney Cadot said:
There's always some things that could be improved of course. My personal
wish-list would include (in no particular order):

* mandatory support for fixed-width integers (in C99, this is optional).

You do realize, of course, that such a change won't make fixed-width
integers any more widely available? All it will do is guarantee that a
conforming implementation of C99 won't be possible on some obscure
platforms. Is there any value in this?

....
* deprecation of implicit casts of fp-types to integer types (perhaps
supported by a mandatory compiler warning).

Warnings are, and should be, purely a matter of QoI. The standard is
only concerned with diagnostics, which can be either warning or error
messages (or, for that matter, gleeful celebrations), it's entirely up
to the implementor.
* a reliable and easy way to walk over all integers in a certain
interval, including the MAX value for that type, by means of a
for loop; eg., currently

for(unsigned i=0;i<=UINT_MAX;i++) ...

doesn't work as intended.

It's perfectly feasible to do this with the language as it currently
exists:

for(unsigned i=0; ; i++)
{
// Body of loop
if(i==UINT_MAX)
break;
}

or

unsigned i=0;

do
{
// Body of loop
}
while(++i);

These are a little clumsy, but is the alternative you're thinking of
any less clumsy? Until you make it more specific, we can't tell.
 
J

James Kuyper

Arthur J. O'Dwyer said:
Ditto the "Huh?" This is what functions were built to
do. You know, curly braces and all that?

Actually, this is what templates are for. min() and max() are the
strongest simple argument for templates that I can think of. I don't
want to add templates to C; if I want C++, I'll use C++. But this is
one of the things that sometimes makes me prefer C++.
 
J

James Kuyper

Simon Biber said:
Surely it is possible, if you add in extra code to handle a
memcpy to and from &x.d every time you read or write to the
unaligned x.d?

Can &x.d be passed to a function which expects a correctly aligned
double*? How is an implementor supposed to make that work properly, on
a platform where alignment is a real issue, not just a performance
hit?

....
* triple-&& and triple-|| operators: &&& and ||| with
semantics like the 'and' and 'or' operators in python:

a &&& b ---> if (a) then b else a
a ||| b ---> if (a) then a else b
[snip]
result = a? b: 0; /* &&& */

ITYM a ? b : a

a?b:0 is marginally faster than a?b:a on some compilers, otherwise
there's not much difference between them.
 
J

James Kuyper

Sidney Cadot said:
....
As to the fixed-width types: there is quite an important area of
application that needs this, which is interpretation of binary protocols
and file formats (this constitutes a large part of the work I'm involved
with at the moment).

But on any platform where those protocols apply, those types will be
available; the market will make sure of that, without any need to have
the standard say so. The only effect of mandating fixed-width types
will be to prevent a fully-conforming implementation of C on certain
rare platforms.

....
This would make some platforms incompatible with C; up to this
point, C has never [to my knowledge] *required* any fixed-width
data types. How about those 9-bit-byte mainframes everyone likes
to bring up?

I think their main raison-d'etre at the moment is as serving as
counter-examples in c.l.c discussions. Perhaps it is time, in the next C
version, to mandate that CHAR_BIT==8. I don't know.

That would also prohibit CHAR_BIT==16 or CHAR_BIT==32. I suspect that
there are currently more of those than platforms with CHAR_BIT==9
(though I myself have no personal experience with CHAR_BIT!=8).

....
It can be done by emitting a lot of code, but this wouldn't be a
problem; you'd only use it for applications where access to an
externally defined packed-binary specification is important.

"A lot of code", yes. On platforms where alignment actually matters,
every function that accepted a pointer argument would have to written
to cope with the possibility that it points into an object which is
actually misaligned, due to being a member of a packed struct.

....
As far as I am aware, the C standard doesn't mandate that floating point
values use sign/exponent/mantissa form; a hitherto unknown good trick
could be discovered for representing fractional numbers today, and it
could be implemented in C I think. My proposal is to have at least
boundaries for integers that can be represented without loss of precision.

The standard does not require that form, but it does define the
<float.h> constants in those terms, as a model. I suspect that there
would be lots of problems applying the C standard to a floating point
type not well-described by that model.

....
This can work for unsigned types, but I'm not so sure if a similar thing
can work portably for signed types.

for(int i=INT_MIN; ; i++)
{
// Body of loop
if(i==INT_MAX)
break;
}

I take it you mean

a &&& b ---> a ? b : a

That's another way to do it, but may be less efficient on some
compilers.
a ||| b ---> a ? a : b

This suffers from the fact that expression a possibly needs to be
evaluated twice, which I'd like to prevent.

That's one reason why the forms he originally gave are better than
your replacements. They both avoid the double-evaluation of 'a'.
 
S

Sidney Cadot

James said:
Can &x.d be passed to a function which expects a correctly aligned
double*? How is an implementor supposed to make that work properly, on
a platform where alignment is a real issue, not just a performance
hit?

Ok, that's a good point. So how about if we forbid the taking of the
adress of a member of a packed struct using the "&" operator, in much
the same way as we can't do it for bit-fields.

Best regards,

Sidney
 
S

Sidney Cadot

James said:
But on any platform where those protocols apply, those types will be
available; the market will make sure of that, without any need to have
the standard say so. The only effect of mandating fixed-width types
will be to prevent a fully-conforming implementation of C on certain
rare platforms.

Good point. Dropped from my wish-list.
This would make some platforms incompatible with C; up to this
point, C has never [to my knowledge] *required* any fixed-width
data types. How about those 9-bit-byte mainframes everyone likes
to bring up?

I think their main raison-d'etre at the moment is as serving as
counter-examples in c.l.c discussions. Perhaps it is time, in the next C
version, to mandate that CHAR_BIT==8. I don't know.

That would also prohibit CHAR_BIT==16 or CHAR_BIT==32. I suspect that
there are currently more of those than platforms with CHAR_BIT==9
(though I myself have no personal experience with CHAR_BIT!=8).


Conceded. Dropped from my wish-list.
"A lot of code", yes. On platforms where alignment actually matters,
every function that accepted a pointer argument would have to written
to cope with the possibility that it points into an object which is
actually misaligned, due to being a member of a packed struct.

I propose to disallow & on members of a packed struct, or at least make
this implementation-defined.

I wonder how gcc handles this on those platforms.
The standard does not require that form, but it does define the
<float.h> constants in those terms, as a model. I suspect that there
would be lots of problems applying the C standard to a floating point
type not well-described by that model.

Ok. Still, MIN and MAX constants for perfectly representable
integer-values for float, double, and long double might be useful.
That's one reason why the forms he originally gave are better than
your replacements. They both avoid the double-evaluation of 'a'.

So, you're going to second this proposal? :)

Best regards,

Sidney
 
C

CBFalconer

those said:
yes. (cf the pl/i standard)

Along the same lines, and probably in heavier use than PL/I today,
are Pascal (ISO 7185) and Extended Pascal (ISO 10206).
 
C

CBFalconer

Sidney said:
.... snip ...

There's always some things that could be improved of course. My
personal wish-list would include (in no particular order):

What a list to shoot at :) I am going to restrain myself and
muck with only a few items.

.... snip ...
* deprecation of implicit casts of fp-types to integer types
(perhaps supported by a mandatory compiler warning).

Breaks existing code.
* deprecation of implicit casts of void* to other pointer types
(perhaps supported by a mandatory compiler warning). This is
a desire not likely to be shared by many here, though ;-)

You called it :)

.... snip ...
* deprecate trigraphs. Let's end the madness once and for all.

Unfortunately absolutely necessary in some environments. You
don't have to use them.
* a reliable and easy way to walk over all integers in a certain
interval, including the MAX value for that type, by means of a
for loop; eg., currently

for(unsigned i=0;i<=UINT_MAX;i++) ...

doesn't work as intended.

i = 0;
do {
stuff();
} while (i++ != UINT_MAX);

I see no law imposing the use of for loops.

.... snip ...
* a way to "bitwise invert" a variable without actually
assigning, complementing "&=", "|=", and friends.

Investigate the '~' operator.

.... snip ...
 
M

Mark McIntyre

'long' might be a better choice
for when you need an exactly 32-bit integer type.

There's nothing that req uires long to be exactly 32 bits any more
than int. Both would be equally nonportable assumptions.
 
X

xarax

Sidney Cadot said:
Ok, that's a good point. So how about if we forbid the taking of the
adress of a member of a packed struct using the "&" operator, in much
the same way as we can't do it for bit-fields.

Not forbid, just a warning when the compiler notices that
the field offset is improperly aligned. Taking the address
may imply truncation of low-order bits and such when applied
to types with implicit alignment (depending on implementation),
so you want a warning when the generated pointer may not work
the same as a properly aligned item. If the field in the packed
structure just happens to be aligned properly, then fine (no
warning).

--
----------------------------------------------
Jeffrey D. Smith
Farsight Systems Corporation
24 BURLINGTON DRIVE
LONGMONT, CO 80501-6906
303-774-9381
http://www.farsight-systems.com
z/Debug debugs your Systems/C programs running on IBM z/OS!
 
D

David M. Wilson

Hi Michael!


Michael B. said:
Of course, I speak only of features in the spirit of C; something like
object-orientation, though a nice feature, does not belong in C.
Something like being able to #define a #define would be very handy,
though, e.g:

#define DECLARE_FOO(bar) #define FOO_bar_SOMETHING \
#define FOO_bar_SOMETHING_ELSE

Although this is my opinion, I think a lot of people would agree:
preprocessor magic should be kept simple and to a minimum. Although
some wonderful tricks can be accomplished using the current
preprocessor syntax (and indeed, your proposed extension), it quickly
becomes a maintenance and readability nightmare - for the coder who
originally wrote it, or for someone else who is picking up the code.

For large #if #else #endifs around platform-specific code, usually
there is a nicer solution found in abstracting said code, and writing
per-platform translation units which are then linked in by your build
system.

I'm not sure whether the features of cpp are even included in the C
standard

They are.

I would also like to see something along the lines of C++ templating,
except without the really kludgy implementation that the C++ folks decided
to go to ( and without the OOP ).

I'd imagine that adding a new fundamental concept such as this to the
C standard stands as good a chance at getting approval as a snowball's
chance of not melting in hell. :)

C is a very simple and uniform language - possibly a major reason for
the roaring success it has had over the years. It is also very
explicit - usually a statement does exactly what it says it does
(unless it includes a cpp macro ;). Concepts such as templates,
although useful, detract from the overall simplicity of the language.

Templates save a lot of time when it comes to commonly-used data
structures, and as they are entirely implemented at compile-time and don't
include, by their definition, OOP (although they can be well suited to
it), I think they would be a nice addition and in the spirit of C.

I would almost say that C already supports 'templates' for structures
at least. For example, imagine:

struct list_head {
struct list_head *next, *prev;
};

struct my_list_type {
struct list_head list_head;
void *my_data;
};

struct my_list_type ml;


As far as I can tell, accessing ml.list_head.next is just as quick
(after compilation) as accessing ml.next, assuming that 'ml.next' is
part of a structure that was generated using a template facility.

This example actually comes from a real project - namely the Linux
kernel. Lots of other people use it too. You could consider it a
'cultural standard idiom'. :)

Yes, coining a stupid phrase like that was completely unneccesary. :D

Your thoughts? I'm sure there's some vitriol coming my way but I'm
prepared 8)

C is simple. It has stood the test of time, and thus "if it ain't
broke, don't fix it".

I believe that C is on it's way out as a general use tool. Sure, it
probably has 20 years left, but programming ideologies are evolving,
and computing is moving to new heights.

C has found it's niche market in lower level and high performing
applications, it is relatively expressive, and it generates small,
tight code. That market isn't about to change, and neither (I believe)
is C. Let's leave it be until the dog has its day, and finally goes to
sleep.

C is dead! Long live QuantumC! ;)


David.
 

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
474,159
Messages
2,570,879
Members
47,416
Latest member
LionelQ387

Latest Threads

Top