Interesting usage of "extern" and "auto". Quite different from contemporary C:
tree() {
extern symbol, block, csym[], ctyp, isn,
peeksym, opdope[], build, error, cp[], cmst[],
space, ospace, cval, ossiz, exit, errflush, cmsiz;
auto op[], opst[20], pp[], prst[20], andflg, o, p, ps, os;
...
Looks like "extern" is used to bring global symbols into function scope. Everything looks to be "int" by default. Some array declarations are specifying a size, others are not. Are the "sizeless" arrays meant to be used as pointers only? >Looks like "extern" is used to bring global symbols into function scope.
a better way to think of extern is, "this symbol is not declared/defined/allocated here, it is declared/defined/allocated someplace else"
"this is its type so your code can reference it properly, and the linker will match up your references with the declared/defined/allocated storage later"
(i'm using reference in the generic english sense, not pointer or anything. it's "that which can give you not only an r-value but an l-value")
Yes, pretty much. To be fair, C at this point was basically BCPL with slightly different syntax (and better char/string support). The introduction of structs (and then longs) changed it forever.
BCPL had a lot of features C didn't have at this point and still doesn't. You mean B.
Could you elaborate on those features? From the top of my head, those are: nested functions — those always were of dubious usefulness compared to the implementation difficulties needed; labels are actual constants, so computed GOTO is available — that's definitely a feature standard C still doesn't have; manifest constants — this one is Ritchie's most baffling omission in the language; multiple assignment — it's not actually parallel so merely a syntax nicety (with a footgun loaded); valof-resultis — while very nice, it's also merely a syntax nicety, "lvalue := valof (... resultis expr; ...)" is the same as "{... lvalue = expr; goto after; ... } after: ;".
What else is there? Pointless distinction between the declaration syntax of functions and procedures?
That includes everything I was thinking of and several things I didn't know about.
"auto" used to mean automatic memory management because if you are coming from assembly or even some other older higher-level languages you can't just declare a local variable and use it as you please. You must declare somewhere to store it and manage its lifetime (even if that means everything is global).
C and its contemporaries introduced automatic or in modern terms local or stack allocated values, often with lexically-scoped lifetimes. extern meaning something outside this file declares the storage for it and register meaning the compiler should keep the value in a register.
However auto has always been the default and thus redundant and style-wise almost no one ever had the style of explicitly specifying auto so it was little-used in the wild. So the C23 committee adopted auto to mean the same as C++: automatically infer the type of the declaration.
You can see some of B's legacy in the design of C. Making everything int by default harkens back to B's lack of types because everything was a machine word you could interpret however you wanted.
Also with original C's function declarations which don't really make sense. The prototype only declares the name and the local function definition then defines (between the closing paren and the opening brace) the list of parameters and their types. There was no attempt whatsoever to have the compiler verify you passed the correct number or types of parameters.
You can do the same with a modren C compiler - the extern and auto mean the same and int is still the default type.
In C23, auto doesn't have a default type, if you write auto without a type then you get the C++ style "type deduction" instead. This is part of the trend (regretted by some WG14 members) of WG14 increasingly serving as a way to fix the core of C++ by instead mutating the C language it's ostensibly based on.
You can think of deduction as crap type inference.
Design by committee, the outcome is usually not what the people on the trenches would like to get.
Nobody in the trenches seemed to use old-style auto in the last decades.
BTW: The right place to complain if you disagree would be the compiler vendors. In particular the Clang side pushes very much for keeping C and C++ aligned, because they have a shared C/C++ FE. So if you want something else, please file or comment on bugs in their bug tracker. Similar for other compilers.
> Nobody in the trenches seemed to use old-style auto in the last decades.
To the beat of my knowledge, there was no case where "auto" wasn't redundant. See e.g. https://stackoverflow.com/a/2192761
This makes me feel better about repurposing it, but I still hate the shitty use it's been put to.
Indeed, however many in the treches would like a more serious take on security, complaining has not served anything in the last 50 years until goverment agencies finally decided to step in.
This is again a problem compilers could have addressed, but didn't. Mostly because the users in the trenches did not care. Instead they flocked in droves to the compiler optimizing in the most aggressive way and rejecting everything costing performance. So I do not have the feeling that users were really pushing for safety. They are very good at complaining though.
GCC and Clang support asan/ubsan, which lets you trade performance for nicer behavior related to memory access and undefined behavior. Whenever I do C development for a platform that supports asan/ubsan, I always develop and test with them enabled just because of how much debugging time they save.
It is like democracy, election results not always reflect the needs of everyone, and some groups are more favored than others.
I think my point is that a standardization committee is not a government.
It surely looks like one from the outside.
Features only get added when there is a champion to push for them forward across all hurdles (candidate), and voted in by its peers (election), at the end of a government cycle (ISO revision), the compiler users rejoice for the new set of features.
Isn't the original inclusion of the auto keyword more in line with what you expect from design by committee? Including a keyword which serves no purpose other than theretical completeness?
I was talking more in general, not specific regarding auto.
Actually I did use C compilers, with K&R C subset for home computers, where auto mattered.
Naturally they are long gone, this was in the early 1990's.
An interesting secondary meaning of "design by committee", the reason why what you mention happens, is "design in committee".
People can skip the usual lifecycle and feedback for an idea by presenting jumping directly to committee stage./
People in the trenches seem pretty happy with what the committee designed here.
It doesn't matter. The people in the trenches don't update their standard versions.
Declaring a variable or function as extern(al) just tells the compiler to assume that it is defined "externally", i.e. in another source file. The compiler will generate references to the named variable/function, and the linker will substitute the actual address of the variable/function when linking all the object files together.
Modern C won't let you put extern declarations inside a function like this, basically because it's bad practice and makes the code less readable. You can of course still put them at global scope (e.g. at top of the source file), but better to put them into a header file, with your code organized into modules of paired .h definition and .c implementation files.
All of these things come directly from B:
https://www.nokia.com/bell-labs/about/dennis-m-ritchie/bintr...
As to "sizeless" arrays - yes.
Have a look at the early history of C document on DMR's site, it mentions that the initial syntax for pointers was that form.