
Subtleties of the ANSI/ISO C standard [pdf] - adsche
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1637.pdf
======
adsche
Money quote for those checking the comments first:

"Furthermore, we argue that the C standard does not allow Turing complete
implementations, and that its evaluation semantics does not preserve typing.
Finally, we claim that no strictly conforming programs exist. That is, there
is no C program for which the standard can guarantee that it will not crash."

~~~
xorblurb
Well at least the section explaining why they think C is not Turing complete
is beyond ridiculous (TLDR: memory is not infinite so there exist a state
machine... WTF????? technically mathematically true but has always been
completely irrelevant when talking about real implementations)

And it seems to be written with a serious tone, it is probably not even a
joke!

~~~
Sniffnoy
The point isn't that memory isn't infinite, but that C's memory _model_ isn't
infinite. There are other languages that do have an infinite memory model (for
instance, any language with a builtin bignum type).

I mean, if you want to judge ridiculousness, then their explanation of why
there are no strictly conforming programs (specifically: even a program with
an empty main function cannot be guaranteed not to overflow the stack) is also
ridiculous, but it's still interesting.

~~~
mannykannot
I agree that it is interesting. For example, what if you can implement, in C,
an interpreter for a language that has a bignum type? I am thinking along the
lines of Greenspun's tenth rule (which I realize is not even close to a
rigorous argument.)

~~~
aji
I'd say the interpreter is interpreting a non-Turing complete subset of the
bignum language. That said, what is and isn't "Turing complete" is hardly
relevant for practical purposes. C has obviously been very useful as a
language, despite whatever theoretical statements can be proven about it.

~~~
mannykannot
It is not clear to me why it would be a subset (I'm assuming proper subset
here) or why it would have to be non- Turing-complete.

I agree that none of this has any obvious relevance to the practical
usefulness of C, but all of us here in this thread have chosen to put that
aside, at least for now, in order to contemplate a somewhat esoteric though
less practical question.

~~~
aji
The key distinction to note is the one between specifications and
implementations.

As a small example, consider Brainfuck. The Brainfuck specification (if such a
thing exists) has no upper bound on the number of memory cells, but practical
implementations generally _do_ have a limit that "useful" Brainfuck programs
will rarely hit. The specification describes a TC language, while the
implementation does not.

Therefore, if a language is TC according to its specification, but has an
implementation in a language that is shown to _not_ be TC, then it follows
that the implementation must be of a non-TC subset of the language. This is,
of course, assuming both that the specification has been proven TC, and that
the implementing language has been proven non-TC.

I believe the point being made in the paper is that the C specification itself
is restrictive enough that it describes a non-TC language. In other words, any
implementation of C that is truly Turing complete would be violating the
specification in some way. In that case, it follows that a C implementation of
a TC language (such as the bignum language) must only be an implementation of
a non-TC subset of the language.

(As an aside, consider that nothing running on an isolated machine will ever
be truly TC, since an isolated machine has a finite amount of memory and so
can't be TC. It's not that much of an inferential jump to see that this kind
of TC-breaking limitation could end up in the specification of C, a language
quite close to the metal.)

------
knz42
We discussed the Turing completeness of C a while ago on HN (
[https://news.ycombinator.com/item?id=4795542](https://news.ycombinator.com/item?id=4795542)
). Also the following was produced around that time:

[https://tdotc.wordpress.com/2012/11/20/on-the-turing-
complet...](https://tdotc.wordpress.com/2012/11/20/on-the-turing-completeness-
of-c-part-2/)

~~~
dbpokorny
When you say "C" and "Turing machine" in the same sentence, you should
immediately think of how you would go about explaining a proof of, say, the
fact that a one tape TM can simulate a k tape TM using C. C is just one of
many languages in which you can express the state transition diagram of a TM.

~~~
knz42
The point being you can't, due to the finiteness of c's abstract memory model,
both for the heap (the tape) and stack (state transition graph)

~~~
dbpokorny
No, any undergraduate CS major at a top 5 university should be able to do
this. It's possible to do this for any programming language. If you need help
then it's on p. 161 Theorem 7.2 of Hopcroft and Ullman (1979).

------
benbenolson
There are so many things wrong with this paper, and nearly all of them have to
do with their "proof" that C is not Turing complete.

First off, they say that C isn't complete because its functions for
reading/writing files are "bounded". Since most other programming languages
are really just implemented in C, wouldn't that mean that either ALL
programming languages aren't Turing complete, or that C is?

Secondly, they mention that programming languages that have "bignum" types get
around the "bounded" memory problem (because you can access "infinite"
memory). But you can implement a bignum in C...

I hope this is a joke.

~~~
saurik
> Since most other programming languages are really just implemented in C,
> wouldn't that mean that either ALL programming languages aren't Turing
> complete, or that C is?

No: it means that the imperfect emulation of those programming languages, as
implemented in C, will fail to be Turing complete. Put another way, there are
programs that are valid Haskell programs that can be proved by the rules of
Haskell to halt on certain inputs and generate particular results, which will
not be able to execute as the C emulator will run out of state in which to
perform the simulation. The interesting point to make here is that it isn't
just that C is being limited by the real world constraints of hardware, but
that C is itself limited as if it were hardware. That said, this was always an
obvious result to anyone who ever bothered asking the question and understands
the formalisms, so I am not certain of the contribution of this paper ;P.

------
sanxiyn
As the author points out, the standard does not mention stack overflow at all.
From this, the author concludes an implementation that always overflows stack
is conforming, therefore no strictly conforming programs exist, therefore all
implementations are conforming. More reasonable conclusion is that under the
current standard, implementations are not allowed to overflow stack, therefore
no bounded storage conforming implementation is possible, and all current
implementations are buggy. Is anyone surprised that all current
implementations are buggy?

It would have been more interesting if the author discussed Microsoft’s
solution to this problem, namely __try/__except and EXCEPTION_STACK_OVERFLOW,
which is actually used by programmers to recover from stack overflow.

------
kabdib
tl;dr; Some interesting points about bits of C that are undefined. Some points
valid, the other ones appear to be self-panicking unless you're heavily in the
theorem-proving correctness camp.

I remain unconvinced that memcmp of pointer values is at all interesting (viz
the pointer normalization dancing acts of the early x86 memory models, ugh).

From a working programmer's point of view, it's useful to know some of the
points in the paper; just read the middle third and skim the rest.

------
fvdfogi
Interesting article that exposes some problems of C, that some take for
granted or ignore.

However the arguing that C is not Turing complete after you take away the IO
and limit yourself on an non-abstract machine is silly. C can simulate any
Turing machine limited by the same previously mentioned rules and the same
holds if you remove those rules for both systems, not just for one.

------
dbpokorny
int read(void); void write(int); void left(void); void right(void);

read returns 0 or 1. write only uses the least significant bit.

