15

I posted this question on StackOverflow, but someone commented and advised me to publish it here.

Here the terms K&R1 and K&R2 refer to a book written by the C creators about the language. K&R1 is the first edition (1978, before the standardization), and K&R2 is from 1988.

entry is a reserved identifier in K&R1, which seems to come from PL/I and FORTRAN.
Someone already posted a question about entry here, and the accepted answer said some compilers implemented it, but the K&R2 states

entry, formerly reserved but never used, is no longer reserved

Who is right ? Did the K&R2 take a shortcut because it was almost not used, and maybe it wasn't relevant for the reader ? Then, if entry has existed, which compilers did implement it ?

In their answer, the author also shared this link, but it only suggests some compilers implemented it, without giving any example though :

Some C compilers prior to the standard implemented that keyword. Since it was never part of any version of the C standard, it has no defined standardized meaning.

I asked this question by curiosity, as I'm very interested about early C.

user3840170
  • 23,072
  • 4
  • 91
  • 150
Chi_Iroh
  • 253
  • 6
  • 1
    You may want to link that question as reference. Likewise it wold be helpful for uninitiated readers to avoid/explain shortcuts like K&R1/2 - maybe even link them. – Raffzahn Jan 30 '24 at 09:28
  • 6
    Early C had a few ideas that never went anywhere; for example, operations to compute mix and max were envisioned but never fully implemented; later they were abandoned altogether. Also, strictly speaking, "implementing" a keyword might mean as little as adding the keyword to the table of reserved words and assigning a unique token to it, which would not be mentioned in any grammar rule. Any use of the keyword in any context would cause a syntax error. – Leo B. Jan 30 '24 at 10:04
  • @LeoB. Thanks, I didn't know that ! – Chi_Iroh Jan 30 '24 at 12:09
  • 3
    In my Harbison & Steele (3rd edition) in 2.6 Reserved Words they do include entry with a footnote "Traditionally reserved, but omitted from ANSI C." This footnote is also used for the asm and fortran entries. – Jon Custer Jan 30 '24 at 14:27
  • 2
    False. _Bool was reserved in C89 by virtue of starting with an underscore and a capital letter, and as far as I know, this reservation stays in place even in the latest draft. Most post-C90 keywords were in fact of this form. volatile and restrict were never reserved without being given grammar productions and meaning. – user3840170 Jan 31 '24 at 13:24
  • @LeoB.: There are a few operators I would have liked to have seen, that could have improved the performance C code could achieve in the 1970s and 1980s, including min, max, and a form of addition/subtraction operators that would take a pointer and integer, and yield a pointer of the original type, displaced by the indicated number of bytes. An operation I often wish for today would be a ternary compound assignment to compute dest = (dest & ~mask) ^ (src & mask) ^(UNSPECIFIED & ~mask & src), but with each operand read only once. – supercat Jan 31 '24 at 17:57
  • @supercat For min, max, complex bit twiddling and what have you, with each operand read only once C could have had an analog of Fortran statement function. Unlike arbitrary inlinable functions, it is much easier to implement. Conversely, avoiding the need to manually cast pointers back and forth is mere syntactic sugar. – Leo B. Jan 31 '24 at 18:23
  • @LeoB.: During the 1970s and 1980s, where it became common to use memory-based text editors (as opposed to manually-manipulated stacks of punched cards), having to write *(int*)((char*)arr1 + i) = *(int*)((char*)arr2 + i); was rather a nuisance. Further, using type casts in such fashion would suppress what would otherwise be useful diagnostics in situations where the argument of the inner cast wasn't a pointer of the outer cast's type. – supercat Jan 31 '24 at 20:08
  • @user3840170 I stand corrected. C18 7.1.3 Reserved identifiers describes what you say, and more. – Weather Vane Jan 31 '24 at 20:32
  • @supercat What you'd like to have is *(arr1 @ i) = *(arr2 @ i) where @ stands for the desired operation. I don't get what extra benefit apart from conciseness you're expecting. Also, while arr1 and arr2 could be properly aligned, after adding an arbitrary value that would not necessarily be true, causing bus errors. For sizeof(T) being a small power of 2, writing arr1[i/sizeof(T)] = arr2[i/sizeof(T)] guarantees pointer safety and incurs little penalty; for most larger sizes memcpy is likely more efficient. – Leo B. Jan 31 '24 at 22:52
  • @LeoB.: Consider the two functions at https://godbolt.org/z/vK68foh5a as processed on a machine (Cortex-M0) which, like many machines of the 1980s, supports non-scaled indexed addressing but not index scaling. Using a pre-scaled loop index will allow a compiler to make use of the indexed addressing mode and produce optimal machine code that would be much harder to find if code didn't use a pre-scaled index (the weird stride += zero; is needed to prevent clang from adding three useless instructions to each loop iteration in an effort to "optimize" it). – supercat Feb 01 '24 at 16:05
  • @supercat After fixing the short/int inconsistency, I do see that the issue is specific to shorts; when ints are used, the instruction count is the same. File a bug report, then. – Leo B. Feb 01 '24 at 16:30
  • @LeoB.: The fact that a compiler generates sub-optimal code is not a bug, and expending significant effort to "fix" such cases without first correcting all situations where a compiler performs unsound transformations that cause it to generate erroneous code would represent "premature optimization". – supercat Feb 01 '24 at 16:58
  • @LeoB.: As for shorts vs ints, the Cortex-M0 supports "load 32-bit value with post-increment" and "store 32-bit value with post-increment" operations, and in cases where that would render other pointer arithmetic unnecessary, that would often offer performance as good or better than using non-scaled indexed addressing. Make the code access every other 32-bit value (e.g. performing computations on one member of a two-int struct) and performance will again only be optimal if code 'helps' the compilers. – supercat Feb 01 '24 at 23:50
  • @supercat I still don't see how a deficiency in some optimizers for some CPUs, which are demonstrably capable to infer the desired instructions from another code pattern, is grounds for wanting to change the basic syntax of the language. – Leo B. Feb 02 '24 at 01:33
  • 1
    @LeoB.: One of the major design goals of C was to allow someone armed with a rather simple complier, who knew what kinds of constructs would be efficient on the target platform, to end up with efficient machine code. The amount of compiler logic to support an operator which adds or subtracts a byte displacement from a pointer without affecting its type would be tiny compared with the amount required to have a compiler make complex inferences. – supercat Feb 02 '24 at 03:45

2 Answers2

8

Per the document Rationale for American National Standard for Information Systems - Programming Language - C, which is an accompanying informative document to American National Standard for Information Systems - Programming Language - C (X3.159-1989):

3.1.1 Keywords
The keywords entry, fortran, and asm have not been included since they were either never used, or are not portable. Uses of fortran and asm as keywords are noted as common extensions.

(Common Extensions is section F.5 in the standard proper)

This wording is not definitive in deciding that 'entry' was 'never' used, though it certainly was not common enough to be called a common extension. We might conclude that 'asm' and 'fortran' were implemented in some compilers but not portable, which leaves only one contender for 'never used'.

Furthermore, it is difficult to see how 'entry' could be incorporated into C syntax. An entry point definition, in contemporary usage, required not only the point of entry to be noted (this could be done with some variation on label syntax), but the names and types of the formal arguments, which need not be a subset of the formal arguments of the 'normal' entry point. Some complicated rules would have to be invented as to what was in scope and what was not.

For this reason, I conclude (by deduction from available information) that 'entry' was never implemented.

dave
  • 35,301
  • 3
  • 80
  • 160
  • Beside that 'never' is hard to proof anyway, I wouldn't be so sure, as entry can be quite useful. Of course not in pure C environments or such able to use C calling conventions, but for being called from other languages and/or environments where the address vector contains vital information or may be the only information. This is especially important considering that such is a very common practice in low level (and or very old) Assembly. Having an entry keyword would be helpful to keep code duplication to a minimum while avoiding code overhead and supporting readability at the same time. – Raffzahn Jan 31 '24 at 22:19
  • 2
    As far as I am aware, there's no block-structured language with multiple entry-point routines, because of the mess that causes to scoping rules and semantics. – dave Jan 31 '24 at 23:42
  • It's not really a question for language theory, but usability. In the end entry is nothing more than a label, like used with goto to catch the few situations where structured programming collides with the reality of good programming. The concept is already there with C - useful back then and still today. The difference of entry to a local label is that it's name/entry point gets promoted to the linker to be accessed from outside - no additional mess, just a fancy attribute. – Raffzahn Feb 01 '24 at 00:08
  • [Maybe as background, I did more than 20 years structured Assembler. To be sure (and transition from the time before, we handcuffed our self: Our Editor was made to flag any regular branch instruction as a blinking line. I assume you can imagine the annoyance. The scripts were made to not compile any source with plain branches. And the list processor putted a 4 line frame of exclamation marks around any source branch. The result was less than two dozen branches in >2 million source code lines (not counting comments). All of them in extrem low level routines. Same for any external declaration] – Raffzahn Feb 01 '24 at 00:16
  • 1
    In pseudocode: function foo(int x); ...; entry bar(float y); ... // what names are in scope at this point? Even if you class 'entry' as the start of a block, the status of 'x' is unclear. You can only resolve this by making up arbitrary rules, which cut across the clarity of nested blocks. Fine for assembler and Fortran; anathema to Algol and its descendents. – dave Feb 01 '24 at 00:28
  • Sorry, but that argumentation doesn't work, as it adds assumptions that are not given still staying within pure C context - usefulness of entry is only given by going beyond that. The alternative would be accepting that there's a class of problems that can not be solved (with reasonable performance) in C. Tell me how one would solve a case "where the address vector contains vital information or may be the only information" without adding calling overhead or duplicating code - features that do not really go well with any programming. – Raffzahn Feb 01 '24 at 00:54
  • 1
    C does not have the concept of "address vector", so I don't know what that is supposed to mean for C. Can you state the issue in terms known to C? – dave Feb 01 '24 at 01:15
  • A function is called by using the vector pointing to it. I guess C lingo might be 'value of *func'. It's called a vector here to avoid the assumption that its storage is known to the calleee. – Raffzahn Feb 01 '24 at 01:50
  • 1
    That's what a 'function pointer' points to, undefined by C (contrary to common myth, it does not always point directly to the code). Any entry-supporting C compiler could define function pointers to extend to alternative entry points. – dave Feb 01 '24 at 11:32
  • No, not a function pointer. A function pointer is a data structure of C. It's about a point. A vector is about two points and a direction. It's as much about where it originates from as where it points to. That's why Interrupt vectors are called that - they not only encode a target but imply where it comes from. Imagine a system handling several interrupt capable serial ports. How to handle this in C without unnecessary runtime (by using stubs to call worker functions) or code overhead (by duplicating he handler for each interface)? Entry is the soution for that. – Raffzahn Feb 01 '24 at 11:54
  • So this vector thingy has to encompass not only the destination but the source? In that case, assuming the existence of 'entry foo()', a whole new type of pointer, type entry, is needed -one that can't be passed around as freely as a func pointer. This is imaginative extrapolation of the language beyond 'entry as keyword' and I am pretty certain one that didn't attach to Fortran IV's ENTRY statement. – dave Feb 01 '24 at 23:26
  • Heck, No. An interrupt vector assigned to an interrupt source and only invoked by that source, thus holding an implied 'from' context. The address of the interrupt function is the vector's target. There is no passing around of a new data type but a real world use case of program flow. Labels are in C always local. Entry as declaration specifier to a label (entry INT_0B:) will make it external, thus available to the linker. The complement to 'static' used with functions (which are external by default). (Let me try something - see below) – Raffzahn Feb 02 '24 at 01:41
  • 1
    Where did that concept of what a C 'entry' would be come from? My mental model is Fortran 77 ENTRY. – dave Feb 02 '24 at 02:35
  • Language wise from PL/I. In Fortran ENTRY is IIRC more of an organisational matter to group functions. But I would think that C is more than a collection of ideas borrowed and bolted on, I would give them credit of having thought about the basic nature of program structure and linking and then boiling it down to the minimum needed to satisfy that. entry is a basic concept in linking. C takes many shortcuts with defaults around linking. Entry would have been one major feature closing the gap in basic linking. Entry in PL/I ad FORTRAN comes from the same concept. – Raffzahn Feb 02 '24 at 12:05
  • I would give them credit of having thought about the basic nature of program structure - which is, I would guess, why it was never implemented. entry is a declaration of variables (the formal arguments) which would cut across block structure. – dave Feb 02 '24 at 12:53
  • From where do you assume that it's a variable declaration? I see a specifier. And cutting across structure is exactly the point here - it's exactly as goto, except made to allow external invocation. – Raffzahn Feb 02 '24 at 13:12
  • 1
    Fortran: ENTRY FOO(A, B, C) introduces names A, B, C which were not necessarily seen in the subprogram unit before. Similarly for PL/I. – dave Feb 02 '24 at 13:40
  • 1
    @dave's example could easily be rewritten as void foo(int x) {y = ...; bar(y);} void bar(float y) {...}, which can use a tail-call optimization for foo's call to bar. – dan04 Feb 02 '24 at 17:35
  • 1
    @dan04 - sure, and also one could write 'foo' and 'bar' each as a front-end to a common private implementation, which is pretty common. – dave Feb 02 '24 at 18:18
  • @dave, is the bold and italic formatting shown here in the original text, or did you add it for emphasis? – DrSheldon Feb 04 '24 at 17:55
  • 1
    @DrSheldon - to my current eyeballs reading old ANSI publication paper, it looks like bolding in the original, but the distinction is not nearly as sharp as in my online reproduction. The italics are from the original Rationale. – dave Feb 04 '24 at 18:00
3

According to Bell Labs in 1984, no

The C Programmer's Handbook was published by AT&T Bell Laboratories in 1984. This is after the 1st edition of K&R, but before the ANSI standard and K&R 2nd edition. They claim "entry is not currently implemented by any compiler but is reserved for future use":

C Programmer's Handbook page 4

Note that "any compiler" would include those on 10 systems:

C Programmer's Handbook page 3

DrSheldon
  • 15,979
  • 5
  • 49
  • 113