yup, same for any real time code, new/malloc/free/delete use hidden mutexes and can cause priority inversion as a result - heisenbugs, that audio/video dropout that happens rarely and you can't quite catch - best to code to avoid them
They also can simply fail, if you are out of memory or your heap is hopelessly fragmented. And they take an unpredictable amount of time. That's very bad if you're trying to prove that you satisfy the worst-case timing requirement.
Unix up until at least System III used the structure thing to do the equivalent to unions, before unions were a thing - for example each disk driver had a data structure that began with a common part and then had a per-device part, generic parts of the kernel used a generic structure that only represented the generic data structure, drivers used their own version.
I think part of this is that early Cs didn't have a full type system, there were limits to the types you could describe (the ones you couldn't were mostly a bit esoteric and not very useful) - from memory in the original PCC types were encoded in the compiler as words rather than trees (pdp11 memory was scarce)
Algol60 had call by name, Algol68 doesn't really, it does have "proceduring" which creates a function to call when you pass an expression to a parameter that's a function pointer that has no parameters, you can use that to sort of do something like call by name but the expense is more obvious
ESPOL was (is?) simply a version of the standard Algol compiler that let you do 'system' sorts of things.
The Burroughs large systems architecture didn't really protect you from yourself, system security/integrity depended on only letting code from vetted compilers run (only a compiler could make a code file, and only a privileged person could make a program a compiler) - so the Algol 60 compiler made code that was safe, Espol could make code that wasn't, could do things a normal user couldn't - you kept the espol compiler somewhere safe away from the students ....
(there was a well known hole in this whole thing involving mag tapes)
As mentioned it evolved into NEWP, and you can get all the manuals from Unisys, as they keep selling it.
Given its architecture, it is sold for batch processing systems where security is paramount.
Yes, ESPOL and NEWP, being one of the first systems languages with UNSAFE code blocks, a binary that is compiled having unsafe is tainted and requires administrator configuration before being allowed to execute by the system.
One cannot just compile such code and execute it right away.
C had 3 major sources, B (derived from BCPL, which had been derived from CPL, which had been derived from ALGOL 60), IBM PL/I and ALGOL 68.
Structs come from PL/I, not from ALGOL 68, together with the postfix operators "." and "->". The term "pointer" also comes from PL/I, the corresponding term in ALGOL 68 was "reference". The prefix operator "*" is a mistake peculiar to C, acknowledged later by the C language designers, it should have been a postfix operator, like in Euler and Pascal.
Examples of things that come from ALGOL 68 are unions (unfortunately C unions lack most useful features of the ALGOL 68 unions. which are implicitly tagged unions) and the combined operation-assignment operators, e.g. "+=" or "*=".
The Bourne shell scripting language, inherited by ksh, bash, zsh etc., also has many features taken from ALGOL 68.
The explicit "malloc" and "free" also come from PL/I. ALGOL 68 is normally implemented with a garbage collector.
C originally had =+ and =- (upto and including Unix V6) - they were ambiguous (a=-b means a= -b? or a = a-b?) and replaced by +=/-=
The original structs were pretty bad too - field names had their own address space and could sort of be used with any pointer which sort of allowed you to make tacky unions) we didn't get a real type system until the late 80s
ALGOL 68 had "=" for equality and ":=" for assignment, like ALGOL 60.
Therefore the operation with assignment operators were like "+:=".
The initial syntax of C was indeed weird and it was caused by the way how their original parser in their first C compiler happened to be written and rewritten, the later form of the assignment operators was closer to their source from ALGOL 68.
Yeah if you ever wondered why the fields in a lot of Posix APIs have names with prefixes like tm_sec and tm_usec it's because of this misfeature of early C.
> it should have been a postfix operator, like in Euler and Pascal.
I never liked Pascal style Pointer^. As the postfix starts to get visually cumbersome with more than one layer of Indirection^^. Especially when combined with other postfix Operators^^.AndMethods. Or even just Operator^ := Assignment.
I also think it's the natural inverse of the "address-of" prefix operator. So we have "take the address of this value" and "look through the address to retreive the value."
The "natural inverse" relationship between "address-of" and indirect addressing is only partial.
You can apply the "*" operator as many times you want, but applying "address-of" twice is meaningless.
Moreover, in complex expressions it is common to mix the indirection operator with array indexing and with structure member selection, and all these 3 postfix operators can appear an unlimited number of times in an expression.
Writing such addressing expressions in C is extremely cumbersome, because they require a great number of parentheses levels and it is still difficult to see which is the order in which they are applied.
With a postfix indirection operator no parentheses are needed and all addressing operators are executed in the order in which they are written.
So it is beyond reasonable doubt that a prefix "*" is a mistake.
The only reason why they have chosen "*" as prefix in C, which they later regretted, was because it seemed easier to define the expressions "*++p" and "*p++" to have the desired order of evaluation.
There is no other use case where a prefix "*" simplifies anything and for the postfix and prefix increment and decrement it would have been possible to find other ways to avoid parentheses and even if they were used with parentheses that would still have been simpler than when you have to mix "*" with array indexing and with structure member selection. Moreover, the use of "++" and "--" with pointers was only a workaround for a dumb compiler, which could not determine by itself whether it should access an array using indices or pointers. Normally there should be no need to expose such an implementation detail in a high-level language, the compiler should choose the addressing modes that are optimal for the target CPU, not the programmer. On some CPUs, including the Intel/AMD CPUs, accessing arrays by incrementing pointers, like in the old C programs, is usually worse than accessing the arrays through indices (because on such CPUs the loop counter can be reused as an index register, regardless of the order in which the array is accessed, including for accessing multiple arrays, avoiding the use of extra registers and reducing the number of executed instructions).
With a postfix "*", the operator "->" would have been superfluous. It has been added to C only to avoid some of the most frequent cases when a prefix "*" leads to ugly syntax.
> You can apply the "*" operator as many times you want, but applying "address-of" twice is meaningless.
This is due to the nature of lvalue and rvalue expressions. You can only get an object where * is meaningful twice if you've applied & meaningfully twice before.
int a = 42;
int *b = &a;
int **c = &b;
I've applied & twice. I merely had to negotiate with the language instead of the parser to do so.
> and all these 3 postfix operators can appear an unlimited number of times in an expression.
In those cases the operator is immediately followed by a non-operator token. I cannot meaningfully write a[][1], or b..field.
> The only reason why they have chosen "*" as prefix in C, which they later regretted, was because it seemed easier to define the expressions "++p" and "p++" to have the desired order of evaluation.
It not only seems easier it is easier. What you sacrifice is complications is defining function pointers. One is far more common than the other. I think they got it right.
> With a postfix "*", the operator "->" would have been superfluous.
Precisely the reason I dislike the Pascal**.Style. Go offers a better mechanism anyways. Just use "." and let the language work out what that means based on types.
I'm offering a subjective point of view. I don't like the way that looks or reads or mentally parses. I'm much happier to occasionally struggle with function pointers.
Some languages do define &&b, like Rust, where its effect is similar to the parent post's C example: it creates a temporary stack allocation initialized with &b, and then takes the address of that.
You could argue this is inconsistent or confusing. It is certainly useful though.
Incidentally, C99 lets you do something similar with compound literal syntax; this is a valid expression:
> The only reason why they have chosen "" as prefix in C, which they later regretted, was because it seemed easier to define the expressions "++p" and "*p++" to have the desired order of evaluation.
There has been no shortage of speculation, much of it needlessly elaborate. The reality, however, appears far simpler – the prefix pointer notation had already been present in B and its predecessor, BCPL[0]. It was not invented anew, merely borrowed – or, more accurately, inherited.
The common lore often attributes this syntactic feature to the influence of the PDP-11 ISA. That claim, whilst not entirely baseless, is at best a partial truth. The PDP-11 did support pre-increment and post-increment indirect address manipulation – but notably lacked their symmetrical complements: pre-increment and post-decrement addressing modes[1]. In other words, it exhibited asymmetry – a gap that undermines the argument for direct PDP-11 ISA inheritance, i.e.
[1] PDP-11 ISA allocates 3 bits for the addressing mode (register / Rn, indirect register (Rn), auto post-increment indirect / (Rn)+ , auto post-increment deferred / @(Rn)+, auto pre-decrement indirect / -(Rn), auto pre-increment deferred / @-(Rn), index / idx(Rn) and index deferred / @idx(Rn) ), and whether it was actually «let's choose these eight modes» or «we also wanted pre-increment and post-decrement but ran out of bits» is a matter of historical debate.
The prefix "*" and the increment/decrement operators have been indeed introduced in the B language (in 1969, before the launch of PDP-11 in 1970, but earlier computers had some autoincrement/autodecrement facilities, though not as complete as in the B language), where "*" has been made prefix for the reason that I have already explained.
The prefix "*" WAS NOT inherited from BCPL, it was purely a B invention due to Ken Thompson.
In BCPL, "*" was actually a postfix operator that was used for array indexing. It was not the operator for indirection.
In CPL, the predecessor of BCPL, there was no indirection operator, because indirection through a pointer was implicit, based on the type of the variable. Instead of an indirection operator, there were different kinds of assignment operators, to enable the assignment of a value to the pointer, instead of assigning to the variable pointed by the pointer, which was the default meaning.
BCPL has made many changes in the syntax of CPL, whose main reason was the necessity of adapting the language to the impoverished character set available on American computers, which lacked many of the characters that had been available in Europe before IBM and a few other US vendors have succeeded to replace the local vendors, also imposing thus the EBCDIC and later the ASCII character sets.
Several of the changes done between BCPL and B had the same kind of reason, i.e. they were needed to transition the language from an older character set to the then new ASCII character set. For instance the use of braces as block delimiters was prompted by their addition into ASCII, as they were not available in the previous character set.
The link that you have provided to a manual of the B language is not useful for historical discussions, as the manual is for a modernized version of B, which contains some features back-ported from C.
There is a manual of the B language dated 1972-01-07, which predates the C language, and which can be found on the Web. Even that version might have already included some changes from the original B language of 1969.
* was the usual infix multiplication operator in BCPL, and it was not used for pointer arithmetic.
The BCPL manual[0] explains the «monadic !» operator (section 2.11.3) as:
2.11.3 MONADIC !
The value or a monadic ! expression is the value of the storage cell whose address is the operand of the !. Thus @!E = !@E = E, (providing E is an expression of the class described in 2.11.2).
Examples.
!X := Y Stores the value of Y into the storage cell whose address is the value of X.
P := !P Stores the value of the cell whose address is the value of P, as the new value of P.
The array indexing used the «V ! idx» syntax (section 2.13, «Vector application»).
So, the ! was a prefix operator for pointers, and it was an infix operator for array indexing.
In Richard's account of BCPL's evolution, he noted that on early hardware the exlamation mark was not easily available, and, therefore, he used a composite *( (i.e. a diagraph):
«The star in *( was chosen because it was available … and it seemed appropriate for subscription since it was used as the indirection operator in the FAP assembly language on CTSS. Later, when the exclamation mark became available, *( was replaced by !( and exclamation mark became both a dyadic and monadic indirection operator».
So, in all likelihood, !X := Y became *(X := Y, eventually becoming *X = Y (in B and C) whilst retaining the exact and original semantics of the !.
The BCPL manual linked by you is not useful, as it describes a recent version of the language, which is irrelevant for the evolution of the B and C languages. A manual of BCPL from July 1967, predating B, can be found on the Web.
The use of the character "!" in BCPL is much later than the development of the B language from BCPL, in 1969.
The asterisk had 3 uses in BCPL, as the multiplication operator, as a marker for the opening bracket in array indexing, to compensate for the lack of different kinds of brackets for function evaluation and for array indexing, and as the escape character in character strings. For the last use the asterisk has been replaced by the backslash in C.
There was indeed a prefix indirection operator in BCPL, but it did not use any special character, because the available character set did not have any unused characters.
The BCPL parser was separate from the lexer, and it was possible for the end users to modify the lexer, in order to assign any locally available characters to the syntactic tokens.
So if a user had appropriate characters, they could have been assigned to indirection and address-of, but otherwise they were just written RV and LV, for right-hand-side value and left-hand-side value.
It is not known whether Ken Thompson had modified the BCPL lexer for his PDP computer, to use some special characters for operators like RV and LV.
In any case, he could not have used asterisk for indirection, because that would have conflicted with its other uses.
The use of asterisk for indirection in B became possible only after Ken Thompson has made many other changes and simplifications in comparison with BCPL, removing any parsing conflicts.
You are right that BCPL already had prefix operators for indirection and address-of, which was different from how this had been handled in CPL, but Martin Richards did not seem to have any reason for this choice and in BCPL this was a less obvious mistake, because it did not have structures.
On the other hand, Ken Thompson did want to have "*" as prefix, after introducing his increment and decrement operators, in order to need no parentheses for pre- and post-incrementation or decrementation of pointers, in the context where postfix operators were defined as having higher precedence than prefix.
Also in his case this was not yet an obvious mistake, because he had no structures and the programs written in B at that time did not use any complex data structures that would need correspondingly complex addressing expressions.
Only years later it became apparent that this was a bad choice, while the earlier choice of N. Wirth in Euler (January 1966; the first high-level language that handled pointers explicitly, with indirection and address-of operators) had been the right one. The high-level languages that had "references" before 1966 (the term "pointer" has been introduced in IBM PL/I, in July 1966), e.g. CPL and FORTRAN IV, handled them only implicitly.
Decades later, complex data structures became common while the manual optimization of incrementing/decrementing explicitly pointers for addressing arrays became a way of writing inefficient programs, which prevent the compiler from optimizing correctly the array accessing for the target CPU.
So the choice of Ken Thompson can be justified in its context from 1969, but in hindsight it has definitely been a very bad choice.
I take no issue with the acknowledgment of being on the losing side of a technical argument – provided evidence compels.
However, to be entirely candid, I have submitted two references and a direct quotation throughout the discourse in support of the position – each of which has been summarily dismissed with an appeal to some ostensibly «older, truer origin», presented without citation, without substantiation, and, most tellingly, without the rigour such a claim demands.
It is important to recall that during the formative years of programming language development, there were no formal standards, no governing design committees. Each compiled copy of a language – often passed around on a tape and locally altered, sometimes severely – became its own dialect, occasionally diverging to the point of incompatibility with its progenitor.
Therefore, may I ask that you provide specific and credible sources – ones that not only support your historical assertion, but also clarify the particular lineage, or flavour, of the language in question? Intellectual honesty demands no less – and rhetorical flourish is no substitute for evidence.
What you say is right, and it would have been less lazy for me to provide links to the documents that I have quoted.
On the other hand, I have provided all the information that is needed for anyone to find those documents through a Web search, in a few seconds.
I have the quoted documents, but it is not helpful to know from where they were downloaded a long time ago, because, unfortunately, the Internet URLs are not stable. So for links, I just have to search them again, like anyone else.
These documents can be found in many places.
For instance, searching "b language manual 1972" finds as the first link:
There exists an earlier internal report about Euler from April 1965 at Stanford, before the publication of the language in CACM, where both indirection and address-of were prefix, like later in BCPL. However, before the publication in January 1966, indirection has been changed to be a postfix operator, choice that has been retained in the later languages of Wirth.
A dash instead of a dot would be so much more congruent with the way Latin script generally render compounded terms. And a reference/pointer (or even pin for short) is really nothing that much different compared to any other function/operator/method.
some·object-pin-pin-pin-transform is not harder to parse nor to interpret as human than (***some_object)->transform().
C's «static» and «auto» also come from PL/I. Even though «auto» has never been used in C, it has found its place in C++.
C also had a reserved keyword, «entry», which had never been used before eventually being relinquished from its keyword status when the standardisation of C began.
FWIW, my slightly more than anecdotal evidence is that 1.6mm is the default thickness at JLCPCB and PCBWay, and they will subtly encourage you to switch to that width if you don't want to pay more or wait longer for them to fill a sheet.
Every IC prototype board (eg Proto Advantage) and all of those Adafruit breakout boards are 1.6mm.
For these reasons, 1.6mm sure seems like a default if there is one. Is there some JEDEC standard or similar which proves me officially wrong? Happy to learn if so.
It's not 1.6mm, it's actually 1/16", and it's been the standard since the days of yore. It's a super common inch measurement so it's not really a surprise to see it here, if you know your inches. There's tons of 1/16" plywood, for example.
A "thick" PCB was commonly 3/32" (0.093") and a "thin" one 1/32" (0.031"). Now of course it's all made in Asia so the metric dimensions predominate (0.8mm, 1.6mm, 2.4mm), but the legacy remains.
And of course PCBs aren't really any of these thicknesses, they're whatever the glass weaves press down to in the lamination press....
Your answer prompted me to do some further research. It's true that IPC-2221A does reference 1/16th as a historical precedent.
That said...
Lawrence Berkeley is an American institution, and it's fair to say that your perspective is American-centric. Without rehashing the ages old argument, it is still true that the US stands with Liberia and Myanmar in your steadfast refusal to standardize on the metric system.
It's your prerogative to conclude that this is an Asian thing, but it's very much an almost everyone else thing.
I will concede that it drives me nuts that not only does the lumber industry still use inches here, it's also officially and somehow legally not even accurate in inches. Why we can't have nice things...
Where does LBNL come into this? The reference in IPC-2221 is to NBS Report 4283 from 1956. Neither of those have anything much to do with LBNL.
I reject your assertion that my comments are America-centric. This a technology that was primarily developed in America and is now predominantly no longer manufactured there (Asia is not in America). It is rather natural for each place to use the units of measure they favor, so it is natural for what was a very common customary unit dimension of 1/16" to become a reasonably round metric dimension of 1.6mm. This is how things develop in the world.
Thanks for calling that out; the IPC-2221A doc I was viewing was on the LBNL domain and my brain incorrectly inferred that the folks who had worked on the IPC spec were employed by LBNL.
Still, IPC is also based in America, which brings us to the same place. While every org has to be based somewhere, the notion that the entire world should use imperial measurements simply because America does is pretty much the definition of America-centric in my books.
The ground truth is that we're talking about a de-facto standard, not a hard one. Given the actual difference between 1.6mm and 1/16", the ease of working in base 10, PCBs are mostly made in Asia and the flogged horse that the entire rest of the planet thinks in metric... it's no surprise to me that 1/16" has become a historical footnote.
I've found 0.8mm to make much more reliable connections, since the specification says that the tongue should be 0.7mm. 0.6mm will disconnect if the cable is angled in any way.
0.8mm is definitely out of USB 3.0 official spec and might damage the plug. The Spec requires 0.7mm with contacts and 0.6mm without, i.e., 0.05mm for the contact. See:
Linus recommends SMD parts kits that are quite expensive, and relatively bulky, I prefer the books of SMD components, they're more compact and ~$15 each and you can buy refills for ~$5.
For things you use a lot of (1k/10k resistors, 1uF/0.1uF caps etc) buy reels, they're surprisingly cheap <$10 from Digikey (if you visit Shenzhen you can pick them up for $2, I bought a complete set years ago for under $100).
I've largely standardised on 0603 parts for hand assembly, I'm older and have older vision, I need a binocular microscope to work - they're worth the investment if you're doing more than a tiny amount of SMD work.
I tend to go for sample books too, if I run out of a value I buy a reel. That way I only have to keep reels of the parts I use most often. For more expensive parts like many ICs I usually try to buy at least as many as the first bulk price discount on Digikey/Mouser/etc. E.g. I tend to use LT3757 switching controllers when I need to make power supplies, so buying 10 of them at $5 each is a much better deal than buying 1 at $7.50 each 10 times!
There's an SF short story (Larry Niven I think) about a seismologist who predicts the big one, but the math is not quite right, the story gets out, panic ensues everyone heads for Nevada, he guy is still working in his lab trying to figure why the sign on his equation is coming out negative when all the rest of the US falls into the sea leaving just his part of CA
This is a great cliff's notes version that actually makes me want to read it, especially since it's a short story. From the description, that's all it needs.
reply