
C – Preliminary C2x Charter - EddieRingle
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2021.htm
======
unwind
This is cool!

I'm a pretty hardcore C programmer (been using it as my absolute main and
favorite language for over 20 years), yet I find it hard to come up with some
wishes for what I'd like to see.

Not sure how to interpret that, perhaps it's just indicative of a certain ...
conservatism common in old people? :) Scary thought!

To be brutally concrete, I sometimes wish I could write someting like this:

    
    
        do {
          const bool flag = do_something();
          ...
          ...
        } while(!flag);
    

That'd be very useful, but of course in current standards it's not possible
since 'flag' isn't valid outside the scope it's declared in. So now we have to
pre-declare 'flag' before the loop, breaking const-cleanliness too of course.
This is obviously not a show-stopper, it's a minute thing. But it would be so
nice! :)

Some support for automatic type inference would be nice, since most right-
hand-side expressions have a type anyway it would be cool to be able to write

    
    
        auto x = 3;
    

and have the type of 'x' be 'int' since that is the type of the literal '3'.
Of course re-using "auto" like this would break their guiding principle, but
it would look great (and, I think, somewhat mimic what C++ has done to that
keyword).

Does anyone have some better ideas?

~~~
naasking
> Does anyone have some better ideas?

gcc's C extensions have some good ideas [1], particularly:

1\. typeof(e) operator: great for use in macros

2\. labels as values: used in just about every language interpeter

3\. statement expressions: great for use in macros

4\. fixed point types: who wants to hack their own fixed precision arithmetic?

5\. vector extensions

6\. arithmetic functions with overflow checking

I think all of the above would make good additions to the C standard.

[1]
[https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html](https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html)

~~~
kps
TR 18037¹ defines fixed point arithmetic, but it does not seem well supported.

¹ [http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf](http://www.open-
std.org/JTC1/SC22/WG14/www/docs/n1169.pdf)

~~~
_kst_
As far as I can tell, a programmer can't specify the number of fractional
bits. The type "unsigned short _Fract", for example, has a number of fraction
bits determined by the implementation within limits imposed by the standard.
There's no way to ask for a type with, for example, 12 integral bits and 4
fractional bits.

Do hardware constraints make, for example, an 8.8 bit format easier to handle
than a 12.4 format?

Compare Ada's fixed-point types, which let you specify the range and delta:

    
    
        type Fixed is delta 0.0625 range 0.0 .. 4095.9375;

~~~
brandmeyer
> Do hardware constraints make, for example, an 8.8 bit format easier to
> handle than a 12.4 format?

Sometimes they do. For example, the ARMv7 DSP extensions support signed Q0.31
and signed Q0.15 arithmetic much faster than any other fixed-point format.

------
dzdt
C needs to cut down on the instances of undefined behavior. Mostly these
should become implementation-defined with some restrictions that the
implementation should do one of the expected things.

For instance, if you overflow an integer, the compiler should not be allowed
to assume that code branch is unreachable, or to conjure nasal demons. Instead
the result should be an implementation-defined integer or a jump to an
implementation-defined exception handling routine.

C should be predictable!

~~~
pcwalton
> C needs to cut down on the instances of undefined behavior

As someone who's worked on compilers a good bit, I disagree (and this is my
favorite meme to argue against lately). You need that undefined behavior for
performance.

> For instance, if you overflow an integer, the compiler should not be allowed
> to assume that code branch is unreachable, or to conjure nasal demons.

You need to be careful to not destroy loop trip count detection.

> Instead the result should be an implementation-defined integer

Not good enough. Loop trip count detection destroyed.

> jump to an implementation-defined exception handling routine.

Unacceptable for performance. Probably a 3x loss.

~~~
haberman
I'm curious to learn more about your position -- have you written it down in
more detail elsewhere? Rust doesn't have this kind of undefined behavior
AFAIK? Are you arguing that C and C++ should have it, but Rust doesn't need to
even though it's competing perf-wise with C and C++ in this space?

~~~
pcwalton
> Are you arguing that C and C++ should have it, but Rust doesn't need to even
> though it's competing perf-wise with C and C++ in this space?

Yes. Other languages like Swift generally don't need it either.

The big wins from exploiting undefined behavior in C come from mistakes that
C's designers made in 1978: signed int being the easiest thing to use for
loops over array indices, the any-pointer-can-alias-anything-else style, the
uselessness of const for optimization, and null pointers. Rust (and e.g.
Swift, for the most part) made none of these choices, and so they can reap the
benefits of aggressive compiler optimizations without the undefined behavior.

(Digression: I can't blame C's designers for these mistakes, of course: it was
1978! But I think that in 2016 we should just accept that there were things we
didn't do right in 1978, because we didn't know as much then as we do now. In
most other engineering industries the idea that we made mistakes 35 years ago
and that modern designs are better is uncontroversial, but for some reason in
computing we have rose-colored glasses for the early days of Unix. Everyone
wants to blame the compiler authors because they don't want to admit C has
flaws!)

These issues don't necessarily apply to other languages. I believe that if you
design a language optimally you don't need to fall back on undefined behavior
to get good performance. But I don't believe C is that language, and I think
attempts to dial back undefined behavior without changing C are missing the
point.

~~~
haberman
Wow, if what you say is true, that's even more of a benefit for a language
like Rust. Memory safety is awesome, but keeping the same performance while
removing undefined behavior is huge.

Another question: how do "unsafe Rust" (ie. Rust inside unsafe blocks) and C
compare in this sense? If satisfying the borrow checker for some bit of code
is too hard, is writing in unsafe Rust better/safer than C?

~~~
pcwalton
Currently, the aliasing rules for unsafe code are "any pointers can
alias"—i.e. no type based alias analysis (TBAA), a.k.a. strict-aliasing. (This
is because LLVM has no concept of TBAA at the IR level; it's something the
frontend supplies explicitly.) There is an open question as to how much this
will affect our ability to perform alias-based optimizations, given that a lot
of our primitives are implemented with unsafe code under the hood. I'm
optimistic that it can be solved (although some others on the team, like Niko,
are less optimistic).

------
comex
My #1 desired feature for a future C standard is statement expressions, like
the GNU extension. They make it much easier to avoid issues like multiple
evaluation when writing macros. Typeof would be nice too - combined with
statement expressions, it adds some capability for type generic macros without
having to explicitly list all the types ala _Generic (which was standardized
in C11 but which nobody uses).

More broadly, while I'm not sure if it really fits in C, it would be cool to
see some kind of lambda function support, along the lines of Apple's "blocks"
extension.

~~~
JoshTriplett
Agreed on both statement expressions and typeof; those seem like they could
and should be standardized exactly as currently implemented.

I'd like to see blocks/lambdas standardized, but I'd want to see a second
implementation first. I also hope for better properties than those of the
Apple blocks extension; I realize C does manual resource management, but the
lifetime issues in blocks seem particularly worse even by C standards.

------
rwmj
__attribute__((cleanup)) please. It's used by systemd now and is supported by
gcc and clang. It makes a real difference to code, avoiding masses of cleanup
along error paths.

~~~
masklinn
When you start needing/wanting stuff like that, wouldn't it make sense to just
use a C++ compiler and a simple RAII type or two?

~~~
rwmj
Really it doesn't. If you add C++ to the mix, you lose the clear relationship
with code as written to what runs (is this operator overloaded?), and you have
an open invitation for people to attempt to use more and more C++ features,
many of which are not well thought through.

Instead of moving to C++, I'd rather allow mixed objects in a more sensible
language (eg. linking with objects written in OCaml).

~~~
xioxox
I'm not convinced by this argument. It's perfectly possible to stick to a well
defined subset of C++ if you're scared by certain features. Just write a
coding standards document and enforce it.

Operator overloading is very important for generating the fastest code
possible, too. It would be hard to get the benefits of a library like Eigen
which can automatically use SSE to optimize maths expressions in C.

------
adrianN
It would be nice if they incorporated some suggestions from the Cerberus
project to make it clearer what is defined and undefined behavior.

[https://www.cl.cam.ac.uk/~pes20/cerberus/](https://www.cl.cam.ac.uk/~pes20/cerberus/)

~~~
cremno
[http://www.open-
std.org/jtc1/sc22/wg14/www/docs/PreLondon201...](http://www.open-
std.org/jtc1/sc22/wg14/www/docs/PreLondon2016.htm)

>N2012 2016/03/10 Sewell, Clarifying the C Memory Object Model

>N2013 2016/03/10 Sewell, C Memory Object and Value Semantics: The Space of de
facto and ISO Standards

>N2014 2016/03/10 Sewell, What is C in Practice? (Cerberus Survey v2):
Analysis of Response

>N2015 2016/03/10 Sewell, What is C in practice? (Cerberus survey v2):
Analysis of Responses - with Comments

------
jeremycw
I don't understand why these committees are so dead set on maintaining
backwards compatibility with existing code when most compilers will support
flags for compiling with old standards anyway. As long as you don't break
binary compatibility I really don't see the issue.

~~~
qznc
Because your new code wants to use old-code libraries.

~~~
jeremycw
But if you maintain binary compatibility can you not just compile the old code
with --std=c89 and then link the new code compiled with --std=c2x ?

~~~
Peaker
Unfortunately, because of header files, no.

------
uxcn
One minor thing that should hopefully be considered... a %b/%B conversion for
printf et al.

It's useful to print binary representations of things (debugging, conversion,
etc...). A number of libc implementations support it as an extension. Forcing
people to re-implement it outside of printf is a bit obnoxious considering how
simple it is, and that there are already hexadecimal and octal conversions.

~~~
_kst_
And "0b11001001" constants.

------
_kst_
Old-style (non-prototype) function declarations and definitions have been
officially "obsolescent" since 1989. Perhaps C2x can finally get rid of them.

~~~
_wmd
This would break the mandate of allowing C90 programs to run "largely
unchanged" (see text)

~~~
_kst_
True, but none of the 14 listed principles is absolute. C2x compilers probably
would (and could be encouraged to) accept old-style declarations and
definitions in some non-conforming mode. They could even be accepted in
conforming mode as long as the compiler warns about it (only a diagnostic is
required).

------
richard_todd
I was curious about this statement:

> The Standard is currently written in troff, which is subject to increasing
> bit rot as the tools for formatting it evolve.

What exactly is bit-rotting? There are multiple maintained troff's out there,
and if they are breaking backward compatibility regularly it's news to me.

~~~
21
Using formats which became less popular and well supported can be considered
bit-rotting.

For example, having .PCX files in some project today instead of .PNG could be
considered a form of bit rotting, because less and less tools support .PCX

------
richm44
I'd like a standardised function to clear a block of memory that is guaranteed
to not be optimised out, and a constant time compare function.

------
uxcn
Another minor thing I think belongs in the C standard is _bswap_. For such a
common operation that's necessary for portable code, I personally don't
understand why it hasn't been defined in either the C or C++ standard.

Currently, the only compiler I'm aware of that optimizes a _bswap_ correctly
is LLVM, which leaves a lot of code in the cold Aside from requiring people to
write their own _bswap_ , which is fairly maligned [1] for good reason, It
leaves out a reasonably important optimization or potentially requires excess
maintenance (platform libs, intrinsics, etc...) for people who do need
portable code (the main reason for _bswap_ ).

I think languages are starting to take the place of platform independent
interfaces, and my personal opinion is that _bswap_ is fairly low hanging
fruit. Given that one of the stated goals of C is portability, I think it fits
well within the mandate.

[1] [http://commandcenter.blogspot.com/2012/04/byte-order-
fallacy...](http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html)

------
loeg
Remove VLAs from the language. They were a mistake.

~~~
PeCaN
They were made optional in C11. Compilers for DSPs or whatever where VLAs
aren't practical don't have to implement them.

Just because an _optional_ feature is impractical on a few niche architectures
doesn't mean it's a mistake.

~~~
_kst_
Yes, but that could have been addressed by making them optional for
freestanding implementations but mandatory for hosted implementations.

Are there any hosted systems (systems that can support the standard library)
on which VLAs are difficult to implement?

~~~
PeCaN
Not as far as I'm aware. POWER, x86(_64), even Itanium all just bump a stack
pointer[1]. SPARC has a funky stack, but I don't know enough about it to say
how hard VLAs would be. (It's a darn cool architecture though. I wish
acquiring a modern SPARC processor wasn't ridiculously expensive.)

The thing that makes VLAs hard to implement is that on some embedded and
special purpose processors the stack is actually a physical, fixed-size
location on the chip. I recall, but can't seem to find, some architecture that
didn't use an explicit stack pointer.

1\. Itanium has 2, but for purposes of VLAs it may as well have a conventional
stack.

------
groovy2shoes
All I really want is C89 with stdint.h and safe(r) string handling routines
(strncpy, snprinf, etc.). Hold the VLAs and the stdbool.h and the what-have-
you.

~~~
GFK_of_xmaspast
(a) [https://randomascii.wordpress.com/2013/04/03/stop-using-
strn...](https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-
already/) (b) Can't you just use the parts of c99 that you want.

~~~
groovy2shoes
(a) I'm aware, but thanks.

(b) Use? yes, but only when I'm not using a library that relies on the parts I
don't want. Implement? not really, since users expect their compilers to
conform to the standards. Rely on for portable code? no, since not all
compilers support C99 and many of those that do actually only support some
subset.

For now, I'm using C89 with my own safe string routines and a configure script
to generate the bits of stdint.h that I need.

~~~
TickleSteve
which compilers aren't supporting C99 now? I keep hearing this argument but I
haven't had that issue at all in recent years.

~~~
groovy2shoes
MSVC and a lot of embedded compilers. Not to mention, I still have to support
systems that are using rather old compilers.

~~~
TickleSteve
I've got 25+ years experience in realtime/embedded work and I have to disagree
with you there. all compilers I can think of have been C99 compliant for a
number of years now. MSVC is compliant now also.

~~~
groovy2shoes
Hmm, that's all news to me. When did MSVC add full C99 support? I totally
missed that. Also, which compilers are you using for your embedded work?

Anyway, like I said, I'm often stuck supporting older compilers, too. So it
might still be some time before I can "upgrade" to C99.

------
entity64
What about templates for C? Has this been proposed before? I'd love to write
function templates, and templated structs would make implementing generic code
so much easier and cleaner.

------
dallbee
I'd just like something better than _Generic and (void *) as our only ways to
do generics. That's my one feature. Too bad that's not likely to happen, ever.

------
cbsmith
The part where I see that after 1999 events have finally unfolded such that
internationalization is only NOW considered important is... disappointing.

~~~
kps
Internationalization _was_ considered important for C89… which yielded
regrettable inventions like trigraphs and wchar_t.

~~~
cbsmith
Umm... wchar_t was not part of C89. It was added later. I think it was a
supplement rolled out half way between C89 & C99, mostly as a consequence of a
lot of platforms embracing native unicode interfaces (I seem to recall it was
released just as Unicode 2.0 was coming out and making it so fixed width
glyphs were no longer a thing).

...and digraphs & trigraphs had to do with different terminals/text editors
that didn't have keys/characters for certain language symbols. Last I checked
it wasn't really about internationalization, but rather the rather insane
variance of character sets just for english (like EBCDIC).

~~~
kps
Really? I'll have to check my paper copy at home, but Wikipedia seems to
agree, with a quote from the standard:
[https://en.wikipedia.org/wiki/Wide_character#C.2FC.2B.2B](https://en.wikipedia.org/wiki/Wide_character#C.2FC.2B.2B)
Maybe it was in C90 (ISO) but not C89 (ANSI)?

For trigraphs see the Rationale at
[http://www.lysator.liu.se/c/rat/b.html#2-2-1-1](http://www.lysator.liu.se/c/rat/b.html#2-2-1-1)

~~~
cbsmith
It's entirely possible I'm misremembering, but I could swear it was in
Amendment 1/C95, not in C90. I have this distinct memory about making jokes
about how C95 and Windows 95 were both outdated technologies the day they were
released. ;-)

I thought C90 was essentially just a reformatting of C89. Interestingly, the
ANSI C page agrees with me:
[https://en.wikipedia.org/wiki/ANSI_C#C95](https://en.wikipedia.org/wiki/ANSI_C#C95)

~~~
kps
Ah, got it. C89 had wchar_t, defined in <stddef.h>, but <wchar.h> and
<wctype.h> didn't show up until '95, so it wasn't very useful. Hence my
vestigial memory of it being a prematurely standardized checkbox feature.

------
algorithm314
support binary literals with 0b prefix. Also include rotate ,count leading
zeroes,count trailing zeros and popcount as functions.

------
jws
I've become a heavy user of a number of clang extensions,

    
    
      __attribute__((cleanup))
      __attribute__((overloadable))
    

… are now indispensable to me.

 _Cleanup_ I use for both object lifetime management (when it fits that
model), and lock management. Typically a "get access" type of function will
take the lock and return the pointer to the object. Then when that pointer
goes out of scope the lock can be freed.

 _overloadable_ is perfect for keeping names under control. Consider if you
have a bunch of structs for encoding various bit arrays. Maybe 32, 64, and
1024 bit long. Each has functions for working on it, so you either prefix all
the functions with bit32_, bit1024_ or you pick a letter suffix, e.g.
bitset(), bitsetl(), bitseth() (huge?), and try to make the programmer
remember them all. With overloadable functions I get to use the same simple
name for the operation and which implementation you use underneath is
irrelevant.

I think I'd like to go one step further and sugar up the syntax so…

    
    
      variable.func(a,b)  <----> func( variable,a,b)
    

… but Mr. Stroustrup might call me names. But darn it, sometimes you want to
think of your objects in different ways. I'd be using lisp if I wanted
everything the same. (Actually, I suppose Kernel, and laughing at the lisp
users who think they have uniformity.) It doesn't have to be ".", go ahead an
create an "=>" notation if that helps with the ambiguity of structure
reference. (No dynamic dispatch here. Just leverage _overloadable_.)

And here is the big one: Thread Safety Analysis. This has the potential to
eliminate huge swathes of runtime problems in multithreaded code and even
calling convention problems in single threaded code.

In a nutshell, you can annotate your program to make statements about objects.
You can say an operation ACQUIRE's an object (takes a lock), and that another
operation RELEASEs an object. Then you can declare that other options REQUIRE
that the object be in the ACQUIREd state. There is more, such as declaring
that a the execution is currently in a state and then restricting its ability
to perform operations based on that.

The current implementation is probably bit rotting in gcc, and the clang
version seems to be missing some important bits to making it useful. The C++
end of it apparently works for Google with their Android coding conventions,
but the C end of it doesn't quite do it for me. I think with perhaps letting a
function declare that its return value is ACQUIRE()d I might be able to put it
to use. (And fixing the bit where it doesn't play well with
__attribute__((cleanup)) ).

But the working group has a '2' in the name. We have 4 years.

And one more huge one: _PLEASE_ add a paragraph to the spec that says:

 _" undefined" is NOT license for some language lawyer compiler writer to kill
your dog, burn your garden, erase your disk and return 42 from the main
program._

Undefined should mean "we understand different architectures and compilers
might prefer to do this differently, implement something SANE and warn the
user that they are on squishy ground".

~~~
jws
If they decided to hand out flying ponies…

• blocks are pretty spiffy.

• nested functions, by which I mean I don't need access to the parent's
variables, I just want to tuck this little function inside the namespace of my
existing function because darn it, it's two lines long and I can give it a
tiny name, and I don't have to stick it above my giant function comment header
where I can't see it while I'm in the code that is using it. I just want to
abstract these two lines that I need to do three times in this function. gcc
has these, clang thinks it's hard in their world.

~~~
david-given
gcc nested functions _do_ have access to their parent's variables. Obviously
only until the parent exits --- they're not closures.

I would love for this to be in the standard, particularly if they come up with
a nested function literal syntax. Having them would make things like mutation
callbacks and foreach() so much cleaner.

~~~
tveita
Nested functions are convenient, but when you take the address of a nested
function that refers to surrounding variables, GCC puts a small trampoline
function on the stack. To do this it has to disable the no-execute flag on the
stack, which makes it significantly easier to exploit stack overflow
vulnerabilities in your program.

Since the implementation is somewhat complex and system-specific, depends on
memory that is both writeable and executable, and requires disabling security
features on modern OSes, I doubt GCC style nested functions will make it into
the standard.

------
rkangel
Namespaces please!

------
grabcocque
(f) Make support for safety and security demonstrable

"Demonstrable" seems to be a bit of weasel-wording there, but for the life of
me I don't see how you make C demonstrably safe and secure without ending up
with something that is almost, but not quite, entirely unlike C.

~~~
pcwalton
Well, "safe" and "secure" can be relative terms, and C definitely could be
_safer_. For example, null pointers could be defined to trap and -fwrapv could
be blessed by the Standard as a mode that all compilers must support.

I agree with you of course that C will never be memory-safe either in theory
or in practice while still remaining C. (The same goes for C++, despite
popular belief.)

------
microcolonel
Cyclone-style never-NULL pointers and bounded pointers would be interesting,
especially if completely optional. They could be incrementally added to sub-
trees of a risky codebase (like a parser) but not poison your ultimate ability
to do pointer arithmetic.

------
fweespee_ch
I'm sorry but open-std is a terrible, terrible name.

------
EFruit
If I could change C, I would look closely at Go.

To be more precise, I would

\- Quit separating definition and implementation (.h & .c vs. the singular
.go)

\- Implement multiple returns

\- Replace #include with something a bit closer to Go's import (Package name
and in-body identifier are decoupled)

\- Methods on any user-defined type

\- Finally, something namespace-like because

    
    
      library_thing_return_t *library_thing_doing_something_else(libraty_thing_param_t *in)

seems unsustainable to me.

~~~
cyphar
.h and .c separation is important for shared libraries (you know, that thing
that you can't really do in Go). I would like it if headers had some stronger
requirements (since you can put any code in a header, which is quite bad).

~~~
xenadu02
> .h and .c separation is important for shared libraries

No it isn't. That's a completely orthogonal issue. The compiler is perfectly
capable of generating the equivalent of a public header if the implementation
has a way to specify visibility.

~~~
nly
It's a bit more than that. You'd have to compile a lot of fluff in to the ELF.
We'd be talking something closer to Windows COM, which allows extracting IDL
from a type library.

