

ISO C is increasingly moronic - phkamp
https://www.varnish-cache.org/docs/trunk/phk/thetoolsweworkwith.html
C is a very robust language which is hard to ruin, but ISO surely is trying.  The latest draft has a new mandatory one-macro #include file, and new incompatible and useless thread API, but still not compiler support for big-endian/little-endian variables or structure packing to match protocol specifications.
======
ajross
Doesn't seem like the author really thought some of this through:

FTA: " _The <nostdreturn.h> file according to the standard shall have exactly
this content: "#define noreturn _Noreturn" Are you crying or laughing yet ?_"

It's a compatibility constraint. They can't simply add new reserved words to
the language because it will break preexisting code (c.f. all the old C
headers with idenfiers like "bool" or "class" or "virtual" that don't build in
C++). The underscore-followed-by-capital convention happened to have been
reserved by ISO C90, so that's what they picked.

But they allow that this is ugly, so there's a new C1X header file you can
include in new C1X code that makes the identifiers look like you expect they
should. Obviously old code won't include this header and is insulated from the
change. (I guess if you wanted to nit here, having a separate header for each
new feature seems dumb to me. Why not a single <c1x.h> or the like?)

Compatibility is important, especially for languages like C with _staggeringly
large_ bases of mature code. For an example of what happens when you break
compatibility in the name of "progress" see Python3, which years on is still
not installed by default anywhere, and probably never will be.

~~~
phkamp
First of all: You're wrong, the compatibility is the other way around: The old
code will have to include <stdnoreturn.h> if they used the "noreturn"
compiler-specific keyword, while waiting for the glacial ISO WG progress.

Second: There are two kinds of compatibility: Forwards compatbility and
backwards compatibilty.

There is a finite number of existing programs whereas the number of future
programs to be written is unbounded and very likely to be much higher over
time.

Therefore forwards compatibility is always, by definition, more important than
backwards compatibility, and you should never penalize future programs and
programmers for the misdeeds and sloppines of the past programs and
programmers.

Besides: I have yet to see a compiler that didn't have flags to make it
compile to a slew of older dialects of C, so if C1X happens to break your old
code, you set such an option, or you fix your source code.

There, fixed it for you.

The "Backwards compatibility, no matter the cost" mentaility is costing us
dearly in the quality of the tools we have work with in the future, while
providing us no relevant new benefits.

Crap like <stdnoreturn.h> is just pointless ornamentation, cluttering our
source code.

~~~
scott_s
If you don't value backwards compatibility, then perhaps you should not use a
40-year-old language with a standards committee that does value it.

~~~
jasonwatkinspdx
I see no reason why he shouldn't express his opinion on the committee's goals
re backward computability.

Defending the status quo by saying "well duh, you should know better, take it
or leave it" is just a way of rejecting someone's contentions without actually
addressing them. In a reasoned debate that's indefensible.

If he's wrong, tell him why rather than telling him to take his ball and go
home.

~~~
scott_s
This is from the Rationale for an International Standard for C, in the intro
where they state their guiding principles from 2003 ([http://www.open-
std.org/jtc1/sc22/wg14/www/C99RationaleV5.10...](http://www.open-
std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf)):

 _Existing code is important, existing implementations are not. A large body
of C code exists of considerable commercial value. Every attempt has been made
to ensure that the bulk of this code will be acceptable to any implementation
conforming to the Standard. The C89 Committee 20 did not want to force most
programmers to modify their C programs just to have them accepted by a
conforming translator._

Note that this guiding principle was listed first. The author disagrees with
one of their fundamental guiding principles. My point is that he then has a
_fundamental_ disagreement with the purpose of the standard, and for that
reason, perhaps he is using the wrong tool.

If someone has the guiding principle _X_ , and someone else has the guiding
principle _!X_ , I contend that difference is irreconcilable.

------
angersock
Absolutely wonderful quote from the article:

 _My tool for writing Varnish is the C-language which in many ways is unique
amongst all of the computer programming languages for having no ambitions.

The C language was invented as a portable assembler language, it doesn't do
objects and garbage-collection, it does numbers and pointers, just like your
CPU.

Compared to the high ambitions, then as now, of new programming languages,
that was almost ridiculous unambitious. Other people were trying to make their
programming languages provably correct, or safe for multiprogramming and quite
an effort went into using natural languages as programming languages.

But C was written to write programs, not to research computer science and
that's exactly what made it useful and popular._

This is a great thing to meditate on when trying to understand why the
language is still used.

------
jacques_chester
The Sydney Opera House is a good example, actually.

It's an iconic building. Australia is frequently represented by a picture of
the opera house in front the the harbour bridge, possibly with Uluru in the
middle distance (it's just outside Sydney, apparently).

There's just one problem. It's not a very good _opera house_. The structural
requirements make it impossible to have an ochestral pit for the musicians,
and the shape of the building make it very difficult to have all the usual
invisible magic that makes opera work smoothly. It's cramped and oddly shaped.

The SOH is a perfect example of the triumph of style over substance. The New
South Welsh who commissioned it are now facing a $1 billion dollar bill for
maintenance over the coming decade.

edit: decade, not 5 years.

~~~
phkamp
Funny you should say that: I've always wondered how it worked in the inside.

I'm not claiming it is a great opera house, but it is a very good example of
using modern building tools.

When Utzon died, one of our (Danish) newspapers explained that the required
maintenance is now necessary because the architects original plan to cap the
"top-seams" with metal was judged too expensive, and some plastic-sealant
("Caulk" ?) were filled into the seam instead, and that has allowed moisture
to seep into the construction. I have no idea if this is true or not.

~~~
jacques_chester
Basically Utzon designed it to look awesome. And it does. As a work of
sculpture it's really lovely, and the engineering to make it stand up is
difficult and impressive.

But as I said, Utzon and his offsiders obviously did not care about the actual
purpose of the building, or whether their beautiful design would be at all
practical. It's not. Even Frank Gehry, whose work I find to be obnoxious, has
managed to design a semi-practical music hall.

It's not really architecture, in a Vitruvian sense. It's walk-through
sculpture.

~~~
onan_barbarian
Your remarks are superficially plausible and fit many people's pet theories
about architects. The only flaw is that they don't have any relation to the
reality of the construction of the actual Sydney Opera House.

The internals of the building were not built to Utzon's design; they were
redesigned and built after Utzon resigned in 1966.

~~~
jacques_chester
> The internals of the building were not built to Utzon's design; they were
> redesigned and built after Utzon resigned in 1966.

My understanding is that Utzon's original design was, basically, impossible.
The new design was a compromise made during intense negotiations with physical
reality after Utzon had quit.

The further point is that those compromises rule out little things such as the
ochestral pit or the tower. Things that are sorta kinda really really useful
for ochestras.

If it was up to me I'd build the usual mausoleum somewhere else and turn the
"opera house" into something else. A museum perhaps.

> Your remarks are superficially plausible and fit many people's pet theories
> about architects.

Availability bias. We never hear about the vast majority of architects who
stick to designing safe, sensible and non-hideous buildings. We _do_ hear
about self-promoting designers of monuments to their own egos, such as Gehry.
And naturally this tilts the public view of architecture.

~~~
jacques_chester
On the other hand ...

As a kid I wanted to be an architect. Maybe I'm suffering from armchair
expertise. "I use buildings, therefore I'm an architect".

But sometimes mistakes are so visible that end users can point them out. My
personal bête noire is the business school building at the University of
Western Australia. Just a stunning array of dumb details, but it's visually
bold and jaunty. I guess that's what sold.

------
haberman
> Now, don't get me wrong: There are lot of ways to improve the C language
> that would make sense: Bitmaps, defined structure packing (think:
> communication protocol packets), big/little endian variables (data sharing),
> sensible handling of linked lists etc.

> As ugly as it is, even the printf()/scanf() format strings could be
> improved, by offering a sensible plugin mechanism, which the compiler can
> understand and use to issue warnings.

> Heck, even a simple basic object facility would be good addition, now that
> C++ have become this huge bloated monster language.

As a C user, I would not want to see _any_ of these things in C.

C++ was originally named "C with Classes," and it didn't start out as a
monstrosity. Adding "simple" classes to C because C++ is too complicated makes
no sense. C++ got complicated because of all of the things that users end up
wanting if you walk that path. There's no reason to think that "simple"
classes added to C would stay simple.

Plugins for printf()/scanf()?? Not even remotely the kind of thing that needs
to be in the core language libraries.

I don't think defined structure packing would really add much; if the idea is
to memcpy() the raw data into your structure, then you're just making the
actual data processing part more expensive because the compiler has to store
the structure in a sub-optimal way (ie. with non-native endianness). Simple
expressions like x.y++ could end up being much more expensive than expected.

~~~
tptacek
For the past 10 years or so, I've been using an alternative to printf() that I
lifted out of Hanson's _C Interfaces and Implementations_; in my tree, it's
"fmt.c", and includes the family of fmt_<star> functions. They're just string
processing code, and so are trivially portable to WinAPI, OS X, Linux, and
FreeBSD.

This is so much of a win that I don't understand why everyone doesn't do it:

* Cross-platform counted/allocated/concatenated string semantics that with no annoying nits from one platform to another.

* "Native" support for printing IP addresses (%i), which gets rid of inet_ntoa and ilk, and binary.

* A registration system for adding new format codes, which is like being able to create Object#inspect functions in C code.

All of which is a roundabout way of saying I agree that we don't need to
improve printf/scanf; we need to burn them with fire.

I'm going to tend to believe PHK if he thinks explicit structure packing is a
win, noting at the same time how unlikely it is that any implementation of it
is going to be a performance bottleneck compared with I/O.

~~~
haberman
> I'm going to tend to believe PHK if he thinks explicit structure packing is
> a win, noting at the same time how unlikely it is that any implementation of
> it is going to be a performance bottleneck compared with I/O.

I've spent a lot of my life writing parsers for various network formats, and
one thing that I can say with authority is that at both my current company
(Google) and at my previous company (Amazon) the CPU cost of parsing bytes off
the network was noticeable enough to spend significant resources optimizing.

I haven't done benchmarks myself about eg. bitvectors, but I'm pretty sure
I've heard that the performance of packed bitvectors is noticeably slower than
non-packed. I also think the cost would be comparable to 64-bit math on 32-bit
processors (ie. an overhead of 3-5 instructions per operation), which is a
non-trivial cost.

~~~
tptacek
In the sense that your parsing strategy influences your I/O strategy and, in
particular, may incur extra copies, I buy this.

The idea that Amazon has cycle-optimized network parsing code, and that they
did it for a significant practical benefit... I have no reason to doubt you,
but I'd like to hear more.

I've done a fair bit of high performance network code (not for Amazon or
Google, but, for instance, for code watching most of the Internet's tier-1
backbone networks on a flow-by-flow basis) and I'm not sure I could have won
much by counting the cycles it took me to pull (say) an NBO integer out of a
packet.

This stuff always makes me think about:

<http://cr.yp.to/sarcasm/modest-proposal.txt>

~~~
haberman
> The idea that Amazon has cycle-optimized network parsing code, and that they
> did it for a significant practical benefit... I have no reason to doubt you,
> but I'd like to hear more.

I can speak better to Google, since it's my more recent experience. Google's
internal data format is Protocol Buffers (and all the code is open-sourced, as
you probably know). The C++ code that is generated to parse Protocol Buffers
is fast (on the order of hundreds of MB/s) as a result of a lot of
optimization. This has reached a rough ceiling of what I believe is possible
with this approach (generated C++). Even so, Protocol Buffer parsing code
shows up in company-wide CPU profiles, and certain teams in particular have
performance issues where Protocol Buffer parsing is a significant concern for
them.

To address these issues, I wrote a Protocol Buffer parser that improves
performance in two ways:

\- it is an event-based parser (like SAX) instead of the protobuf generated
classes which are a more DOM-like approach (always parsing into a tree of data
structures). With my parser you bind fields to callbacks, and you can parse
into any data structure (or do pure stream processing).

\- I wrote a JIT compiler that can translate a Protocol Buffer schema directly
into x86-64 machine code that parses that schema. Without the intermediate C++
step, I can generate better machine code than the C++ compiler does. In an
apples-to-apples test, I beat the generated C++ by 10-40%. If you do more pure
stream parsing the win is even greater.

My protobuf work is open source: <https://github.com/haberman/upb>

> I'm not sure I could have won much by counting the cycles it took me to pull
> (say) an NBO integer out of a packet.

That's certainly different experience than mine. I don't know much about
routers.

~~~
tptacek
Bad-ass. I'm happy to be wrong if it solicits comments like this. :)

------
bhurt
The C standards committee has been broken since C99 introduced long long, thus
_silently_ breaking conforming code.

How do you print out a size_t, portably, without losing information? The
standard says size_t is an unsigned integer type, but doesn't say way size.
However, the C89 spec explicitly stated that there are no integers sizes
longer than long- so the conforming way to do this is to explicitly cast the
size_t to unsigned long (which, while it may add bits, is guaranteed not to
lose them), and print the unsigned long.

In an attempt to save all the broken, non-conforming code that assumed that
sizeof(int) == sizeof(long), C99 introduced the long long type. And, among
other things, allowed size_t to now be unsigned long long. Which meant the
conforming C89 code that wants to print out a size_t is now wrong. Worse yet,
it's silently broken- because the type cast is explicit, the compiler has to
assume it's correct. They added a new way to print size_t's, granted- but this
is no help for the legacy code (or code that needs to continue to support
C89-only compilers).

Of course, the punchline here is that I have yet to see code that assumed
sizeof(int) == sizeof(long) that didn't also assume sizeof(void *) ==
sizeof(int). So all that broken non-conforming code they were trying to save?
It still needed to get fixed for 64-bit.

~~~
phkamp
You overlook the %z printf specifier which attempts, but not quite solves the
problem, because size_t comes in both a signed (ssize_t) and unsigned (size_t)
variant.

I usually end up doing printf("%j", (intmax_t)foo);

~~~
to3m
Won't "%zu" vs "%zd" do the trick? `z' is a modifier, like `l'.

(That said, I've only ever used %zu myself... don't think I've ever used
ssize_t. I'm pretty sure it's non-ISO.)

~~~
caf
It does (other variants like `%zx` are also fine).

------
scott_s
I find this author's characterization of the history of C inaccurate. At the
time, C _was_ innovative. And its existence _did_ enable computer science
research, because with C, operating systems were finally portable. C itself
was a worthwhile contribution to computer science research. Kernighan and
Ritchie built upon prior languages, but they were able to distil what levels
and kinds of abstraction were needed to implement portable systems programs.
Many of the concepts in C existed in C's predecessors, but not in the same
form we know them as. It's easy to under-estimate how novel that contribution
is because so many of us _think_ in C now.

For a history of C from the source, Dennis Ritchie, read this:
<http://cm.bell-labs.com/who/dmr/chist.html>

~~~
phkamp
You are rationalizing: C was not "novel", it was pretty much BCPL-light. There
also were portable operating systems before UNIX, some of them were written in
PL/1 and FORTRAN.

~~~
scott_s
BCPL had a single data type (the "word") and no structures.

Ritchie's paper above covers the innovations in C quite well. See sections
"The Problems of B", "Embryonic C" and "Neonatal C".

~~~
phkamp
And that's where C started out (as 'B').

Adding structures or for that matter pointers to a programming language was
not "novel" in 1970.

The sheer success of the UNIX and the myth it has built, has many contemporary
programmers thinking that everybody else punched cards with flint tools around
the bonfire. Even MULTICS, a very innovative and in many ways wonderful OS has
gotten a bad rap because of the UNIX-fanboiz cult-building.

Dennis, Ken & Brian broke ground, but very few people can correctly say what
new ground they broke. (Hint: namespaces, file structure, what a file
contains).

------
caf
As noted elsewhere, the _Noreturn spelling is used precisely _because_ such
identifiers have been reserved since the first ISO C standard, so existing
conforming code shouldn't use them and hence shouldn't break.

However, rather than introducing <stdnoreturn.h> to create the pretty
spelling, it would perhaps have been better if the standard specified that if
you define a macro like _C_SOURCE to a suitable value before including any
standard headers then you get that define.

That would mean old conforming code would continue to work, and new code would
just have to start out with

    
    
      #define _C_SOURCE 20110101
    

(or whatever the actual date specified is) to declare its allegience. This
kind of thing would also allow older-standard compilers to detect and reject
code that requires the newer standard.

~~~
Someone
Neither approach would allow one to mix the two versions. Consider the
following use case: program P uses two third party libraries L and M, so it
uses:

    
    
      #include "L.h"
      #include "M.h"
    

Program P gets updated by downloading improved versions of L and M. The new
version of L.h does a

    
    
      #include <stdnoreturn.h>
    

or

    
    
      #define _C_SOURCE 20110101
    

Now, program P accidentally gets processed while noreturn is a keyword.

I do not see how to fix this (you could #undef every macro that the new C
standard introduces before including M.h, but M.h might have a noreturn macro
of its own that is not the ISO C version). It is just as if 'old C' and 'new
C' are two different languages that happen to look similar, and that can be
compiled by a single compiler.

~~~
caf
For precisely this reason, third-party libraries should not be including
<stdnoreturn.h> in their external headers unless they are specifically
intended to work only on C1x.

Under the _C_SOURCE scheme they _certainly_ shouldn't be defining that macro,
since the program which is including them has likely already defined it and
you cannot have a duplicate macro definition. If they care, they should
instead be testing its current value with #if, not changing it - ie, if a
library requires C11x then it would use something like:

    
    
      #if _C_SOURCE < 20110101
          #error C11x or better required for this library
      #endif

------
latitude
Taking bets on when ISO C will acquire a form of templates, or taking it in
even more generic direction - parametrized namespaces. Something like this (an
illustrative example, don't knock me down for including _val_ into _list_ ):

    
    
      namespace(T)
      {
        struct list
        {
           T      val;
           list * next;
           list * prev;
        };
    
        void append(list * l, list * i)
        {
          ...
        }
      }
    

Then

    
    
      list<int> * foo, * bar;
      ...
      append(foo, bar);
    

No need for namespace nesting, default arguments and other ++isms. Just
something to replace multi-line macro blocks.

~~~
koenigdavidmj
Why not just use C++ without namespace nesting, default arguments, and other
++isms?

------
antirez
Well this sounds very messy, the fact you can't change the stack of the thread
is a no go for many purposes, just an example, in Redis this must be done
because otherwise lzw encryption will cause a stack overflow.

Also the ISO C guys completely miss how important is to provide a better libc
with data structures and so forth, very very very well designed.

About the epic quote of C being a language without ambitions, one of the
reasons if D or Go, or other languages are going to hardly replace C is that
they are indeed, too ambitious. No one is trying to fixing C with minimal but
important changes.

------
kqr2
Link to the current C1X draft which is mentioned in the article:

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>

------
leoc
> Concrete has been known since antiquity, but steel-reinforced concrete and
> massive numerical calculations of stress-distribution, is the tools that
> makes the difference between using concrete as a filler material between
> stones, and as gravity-defying curved but perfectly safe load-bearing wall.

Ahem.
[http://www.google.ie/imgres?imgurl=http://romanconcrete.com/...](http://www.google.ie/imgres?imgurl=http://romanconcrete.com/graphics/pantheon_dome.jpg&imgrefurl=http://romanconcrete.com/about.htm&h=900&w=600&sz=91&tbnid=XqbRatDd5am7uM:&tbnh=90&tbnw=60&prev=/search%3Fq%3Dpantheon%2Bdome%26tbm%3Disch%26tbo%3Du&zoom=1&q=pantheon+dome&docid=0KpRyueAMS9WzM&sa=X&ei=_4TxTq2nF5SyhAfK-N2zAQ&ved=0CD0Q9QEwAw&dur=2401)

------
forgotusername
Ignoring complaints about the introduction of a new style of _Identifier, the
rant about pthreads seems myopic or just plain wrong.

For a start as a vendor-neutral spec (the C standard itself), pthreads would
never be adopted as-is. It simply couldn't happen for political reasons
(without knowing a thing about the internals of the working group, I'm fairly
confident of that). In the meantime it is still useful to define _some_
uniform cross-platform API, even if most organizations continue to use
pthreads in legacy code.

Assuming "too dangerous" wasn't a direct quote: stack size is an
implementation detail, something they probably intentionally left undefined.
There are good reasons for this, not least baking assumptions about the
underlying machine into the standard has never been a goal. Secondly, with
advances like Go's dynamic stacks and its <5 assembly instruction overhead,
why would you go and bake a feature akin to a modern sbrk(2) in when sexy
alternatives that might see wider adoption are already seeing deployment.

As for timed sleeps, providing absolute timestamps rather than intervals is
important because it prevents drift: given any function manipulating time, or
some timeout, calculating some perceptible end time in the function prologue
is much more immune to stupid developers introducing drift (via loops), than
expecting the average Joe to account for the latency/contention introduced by
system calls, the scheduler, power management, etc.

Fears regarding ntpd causing sudden jumps aren't well-founded (ntpd adjusts
time very slowly, in sub-second intervals), although the general argument is
fair (the sys admin, or other crazy external sources, can cause large time
jumps).

~~~
phkamp
This comment was filled with fail.

Pthreads has been the standard for 20 years, either you do better than it
does, or you are wasting everybodys time, including your own.

"Too dangerous" is a direct quote from a WG14 member.

Stacksize is not an implementation detail, it often is crucial resource
management issue for each individual application, in particular in high
performance computing and network service applications. The C1X thread API
provides no way you can set it.

With respect to timed sleeps: You can simulate wall-clock sleeps with
duration-sleeps, but not the other way around. Just that simple fact should
make it clear why the API, if it can only offer one kind of timeout, should
offer duration-sleeps.

NTPD will step your clock up to +/- 3599 seconds. I happen to know: I helped
write it.

~~~
forgotusername
With respect to stack size, I still believe it is an implementation attribute
independent of the abstract machine for which C is specified. There is no
reason why some undefined external vendor-specific control (e.g. some glibc
function) can't be provided by implementations, where required (however as in
the example I gave, implementations are possible where such a control would be
meaningless - its inclusion would be myopic).

Following your argument, complex systems could not be designed without similar
controls on memory allocator behaviour ("how can I allocate _anything_ when I
don't know if malloc() will introduce syscall latency for a size-32
allocation!?") or environment table size ("how can I possibly execute a
subprocess if I can't be certain setenv() will always succeed!?").

The answer to both of course is that you don't design for the standard, you
design (and measure) for a particular closed system. I can't see why stack
size is any different from the two (of many) examples above.

Re: absolute timeouts, the impossibility of emulating intervals reliably with
wall-clock is a very good point.

~~~
phkamp
First: Why should the API for setting stack-size be implementation defined,
when a stack mandated to implement the language ?

Second: You seem to labour under the misunderstanding that all threads in a
program have, and should have the same stack size ? That's simply not true,
you can look in Varnish for a good example: We may have 10 "overhead" threads
with big stacks and 100.000 worker threads with small stacks.

Third: You cannot add "some glibc function" to set the stack-size of a thread
you have not yet created, and setting it afterwards may be impossible (if you
want it larger) or cause memory fragmentation (if you want it smaller).

Fourth: What does malloc(3) have to do with thread stacks ??

~~~
forgotusername
For the third time, the API for setting stack size should be implementation
defined because there are perfectly practical implementations for which any
specification would be meaningless.

Another reason is that almost all prevailing contemporary environments use
virtual memory, and the prevailing embedded architecture (ARM) is about to go
64 bit (the desktop/server world already has). In a world with virtual memory,
paging, and even where we're 10 years away from "complex system" interconnects
powerful enough to provide shared memory across 10k+ computers filling a
football field, how much longer would setting the stack size have any
practical meaning.

It would be like insisting on a frewindtapedrive() library call, because your
machine happens to have a tape drive (and aren't files stored on tapes
eventually!). Thankfully you weren't on the committee in the 1980s. ;)

Nowhere did I suggest all threads should have the same stack size - if
anything by the Go example, I suggested they might have no specific 'size' at
all.

malloc(3) has nothing to do with thread stacks, it was just an example of yet
something else that has very implementation-defined behaviour, for which any
standardized tuning API would probably come up short.

~~~
phkamp
Please give an example of an implementation of this thread API where having
the ability to specify the desired stacksize would "be meaningless" ?

Even on 64bit machines you can and will have memory fragmentation when you
approach a million threads.

PS: A bad analogy is like a wet screwdriver.

~~~
forgotusername
1) <http://gcc.gnu.org/wiki/SplitStacks>

> This is currently implemented for 32-bit and 64-bit x86 targets running
> GNU/Linux in gcc 4.6.0 and later. For full functionality you must be using
> the gold linker, which you can get by building binutils 2.21 or later with
> --enable-gold.

2) You're still conflating heap and stack.

~~~
phkamp
Too bad it is not part of the ABI specification on any known platform, so if
you call a library function compiled without this magic compiler you're
totally screwed.

But an interesting research project, I'll grant you that.

~~~
mikeash
There's a section in that link which details how they handle calls to
libraries that aren't aware of what's going on. Sounds like it works just
fine.

------
po
In case you missed it, this article is part of the 'Poul-Hennings random
outbursts' section which is a nice collection of thoughts from a very talented
programmer. I have always enjoyed reading these:

<https://www.varnish-cache.org/docs/trunk/phk/index.html>

------
comex
I don't see this as particularly monstrous - it's reasonably succinct, and in
this case a macro implementation does the job just as well as a built-in
linked list would, and with much more flexibility.

    
    
        #define VTAILQ_INSERT_BEFORE(listelm, elm, field) do {              \
            (elm)->field.vtqe_prev = (listelm)->field.vtqe_prev;            \
            VTAILQ_NEXT((elm), field) = (listelm);                          \
            *(listelm)->field.vtqe_prev = (elm);                            \
            (listelm)->field.vtqe_prev = &VTAILQ_NEXT((elm), field);        \
        } while (0)
    

(I don't understand why it uses VTAILQ_NEXT((elm), field) instead of what it
expands to, (elm)->field.vtqe_next - that would make it more obvious what's
going on by paralleling the use of vtqe_prev - but that's the fault of the
macro implementation.)

~~~
tkahn6
Can anyone explain why this needs to be a macro? What does this get you over a
plain function?

~~~
tptacek
The idiomatic way you'd express a generic tailq in C with functions is with
void-stars, which cost 4-8 bytes and incur the costs of indirecting through
another memory address and, probably, of allocating lots of fiddly little
structs at random times.

The macro version expresses the same generalized logic but embeds the link
pointers in the structure you're queueing.

~~~
tkahn6
Thanks! Helpful as always.

------
nyellin
_As ugly as it is, even the printf()/scanf() format strings could be improved,
by offering a sensible plugin mechanism, which the compiler can understand and
use to issue warnings._

gcc allows this with the 'format' attribute:
[http://gcc.gnu.org/onlinedocs/gcc/Function-
Attributes.html#F...](http://gcc.gnu.org/onlinedocs/gcc/Function-
Attributes.html#Function-Attributes)

~~~
phkamp
Yes, but gcc gives you no way to explain to the compiler that %Q takes a
struct foobar* as argument, so either you don't use extensions, and have the
seatbelts provided by -Wformat, or you use extensions and have no seatbelts at
all.

------
Aissen
_For instance, neither pthreads nor C1X-threads offer a "assert I'm holding
this mutex locked" facility. I will posit that you cannot successfully develop
real-world threaded programs and APIs without that, or without wasting a lot
of time debugging silly mistakes._

It's funny, Alan Cox thinks the same:
[https://plus.google.com/111104121194250082892/posts/jWjJ9897...](https://plus.google.com/111104121194250082892/posts/jWjJ9897skU)

------
stephencanon
Underscore-capital has been a reserved identifier prefix for many, many years.
It's rather late to begin complaining about it. The side note about name-
mangling on some platforms also using a leading underscore only shows that you
can use a tool for years and still not understand it; that issue is completely
orthogonal. I assure you, everyone on the committee is perfectly clear on the
difference between name mangling and the reserved namespace.

The section on stack size is where it actually goes off the rails. _C does not
require that there be a stack._ (Actually, the standard does not even contain
the word "stack".) From that perspective, being able to control the "stack
size" of a thread is nonsensical.

I'd be the first to agree that there have been some questionable additions to
the C language, but this criticism comes off as half-baked at best. If you
really care about this stuff, you should get involved with the standards
process, or at least provide this feedback directly to the committee members--
they are, for the most part, a very reasonable and thoughtful group of people.

------
tedunangst
The deal with underscores isn't anything new, that was there in C99 for sure.
Maybe C89 but I don't know. In any case, I think getting upset about a more
than decade old change is a little late and detracts from the main point.

------
mberning
I am usually not one to appeal to authority, but I do find it amusing the
number of people attempting to argue with somebody like phk over stylings of
the C language. Most people on here would be overwhelmed with pride to have
written a fraction of the important code he has.

------
pwaring
I'm not a C expert by any means, but is there a need for another new version?
Last time I checked, some compilers hadn't even got round to implementing C99
(e.g. Visual C++ doesn't support variable length arrays). Even gcc hasn't got
everything:

<http://gcc.gnu.org/c99status.html>

------
api
Nothing good ever came from a committee.

~~~
zb
Actually I think C emerged from its original ANSI standardisation process in
much better shape than when it went it. You don't see too much K&R C being
written these days for good reason.

~~~
phkamp
You're probably right about that, ANSI did a couple of good things, but I'm
not sure I think they came out in the black in the end.

ISO on the other hand, seems like a total disaster.

~~~
StephenFalken
It's interesting to note the bumpy road that lead to the final standardization
of C as ANSI X3.159-1989, as documented on the following post:

[http://groups.google.com/group/comp.lang.c/msg/991b9116ffa83...](http://groups.google.com/group/comp.lang.c/msg/991b9116ffa83c60?hl=en&dmode=source&output=gplain)

Dennis Ritchie spend part of that time fighting against the introduction of
several new features he felt were not the proper future of the language.
Unfortunately, he had little to no involvement on the C99 standardization
process. The final outcome was a butchered language. I'm sticking to C89/C90
on all my C development, no matter what.

"I was satisfied with the 1989/1990 ANSI/ISO standard. The new C99 standard is
much bulkier, and though the committee has signaled that much of their time
was spent in resisting feature-suggestions, there are still plenty of accepted
ones to digest. I certainly don't desire additional ones, and the most obvious
reaction is that I wish they had resisted more firmly." --dmr

~~~
JoshTriplett
The post you point at just talks at length about two features: const, which
Dennis Ritchie liked but wanted changes to, and noalias, which he wanted to
kill off. Const works exactly like he suggested; noalias became "restrict",
which seems dead outside of a few standard library functions.

That doesn't seem to me like a pervasive sign of problems with C99.
Personally, I find the C99 standard incredibly useful and I can hardly stand
to write C code that can't rely on C99. I like having designated initializers.
I like having a "bool" type. I like having structure literals, for use in
arguments or return types. I like having the family of sized integer types,
such as uint32_t and uint64_t. And I like having standardized versions of pre-
existing features such as "long long", "inline", and variables declared in the
middle of code.

Do you really despise all of those features?

------
billrobertson42
I wonder if he's looked at golang.

------
swaits
phk is one of my personal heroes!

------
dextorious
"""The <nostdreturn.h> file according to the standard shall have exactly this
content: #define noreturn _Noreturn"""

Damn, this standard is way past the point of no return!

------
16s
Some of the comments here seem rather harsh and certainly after the fact.
There are a lot of knowledgeable, well-intended people on the committee and
the standard was ratified by nation states. So it is finished. The time to
take issue with it (draft/formal comment period) has passed.

