A cursed feature of C in 1972: Labels and functions were reassignable (i.e., lvalues)!
-
This snippet appears in cvft, a compiler for translating Fortran threaded code to machine code from June 1972, which is notably derived from the early C code generator. See putchar (and also getcha) in dmr/cgd/cvft.c.
The earliest extant C compiler is last1120c from July 1972, the last C version for the PDP-11/20, before they migrated to the PDP-11/45. This version still has the label lvalue behavior of B seen in cvft. Then, it was changed to the modern behavior by the time of prestruct-c from December 1972. That version supports structures, but does not yet use them itself.
All three can be found in Dennis_Tapes: https://www.tuhs.org/Archive/Applications/Dennis_Tapes
Another strange pattern from the same program.
This one reassigns the address of an array, `int nlist[250]`, in char increments. Arrays are no longer lvalues, so this doesn't work anymore. Also, the address is unaligned every other iteration.
lbp;
nlist[250];getnam()
{
extern nlist, lbp;
char nlist[], lbp[], c;loop:
c = *lbp++;
if (c==';' | c=='\n')
goto el;
*nlist++ = c;
goto loop;
el:
*nlist++ = '\0';
}Somewhat simplified from Dennis_Tapes/dmr/cgd/cg1.c:getnam.
-
@vk2bea @thalia
The ASSIGN statement in Fortran IV and the ALTER statement in COBOL supported ways to redirect the target of a GOTO, much in the same way as the "cursed figure" of C that you described. I assume that at the time, it felt important to have parity between C and Fortran (and maybe COBOL).@huitema @vk2bea @thalia ALTER-like functionality reflects the fact that programming was still evolving to use subroutines/functions and concepts like Structured Programming were still considered radical by old-school programmers at the time**.
It probably didn't help that this was a time prior to formal programming courses so a lot of programmers were self-taught and developed their craft in isolation (and often in assembler) so using "go to"s and ALTERs came pretty naturally.
IOWs, if you wanted a language that appealed to the masses at the time then you pretty well had to include goto and ALTER.
** https://en.wikipedia.org/wiki/Structured_programming#Debate
-
" like kicking dead whales down the beach."
Hmm. I used BCPL on Tenex in 1980, and don't remember having problems.
And my dad had a PDP-7 at work. This one.
-
Another strange pattern from the same program.
This one reassigns the address of an array, `int nlist[250]`, in char increments. Arrays are no longer lvalues, so this doesn't work anymore. Also, the address is unaligned every other iteration.
lbp;
nlist[250];getnam()
{
extern nlist, lbp;
char nlist[], lbp[], c;loop:
c = *lbp++;
if (c==';' | c=='\n')
goto el;
*nlist++ = c;
goto loop;
el:
*nlist++ = '\0';
}Somewhat simplified from Dennis_Tapes/dmr/cgd/cg1.c:getnam.
This snippet deliberately triggers a "Bus error -- Core dumped":
int o1[];
o1 = -3;
*o1;From Dennis_Tapes/dmr/cgd/cg1.c:expr.
-
A cursed feature of C in 1972: Labels and functions were reassignable (i.e., lvalues)!
For example, this is a clever way to initialize once:
goto init;
init:
ouptr = oubuf;
init = init1;
init1:which is compiled to:
jmp *4120
mov 4136,4144
mov 4122,4120Note the indirect jump and assignment to that address. All gotos used indirect jumps. This apparently would have also worked with functions.
@thalia Eeeek! Make it go away!
-
A cursed feature of C in 1972: Labels and functions were reassignable (i.e., lvalues)!
For example, this is a clever way to initialize once:
goto init;
init:
ouptr = oubuf;
init = init1;
init1:which is compiled to:
jmp *4120
mov 4136,4144
mov 4122,4120Note the indirect jump and assignment to that address. All gotos used indirect jumps. This apparently would have also worked with functions.
@thalia@discuss.systems I’m sorry. What. -
A cursed feature of C in 1972: Labels and functions were reassignable (i.e., lvalues)!
For example, this is a clever way to initialize once:
goto init;
init:
ouptr = oubuf;
init = init1;
init1:which is compiled to:
jmp *4120
mov 4136,4144
mov 4122,4120Note the indirect jump and assignment to that address. All gotos used indirect jumps. This apparently would have also worked with functions.
@thalia oh this is cool, basically self-modifying code in C!
-
@djl I'm afraid I don't speak PDP-6 / PDP-10 assembly (yet?). Could you elucidate?
PUSHJ, PUSHJ, POPJ P,
JRST . + 1203pushjay, pushjay, popjay pee
Jrst to point plus twelve oh threePUSHJ is the recursive subroutine call, POPJ is the return therefrom, both require the stack register to be stipulated.
JRST is the unconditional jump instruction, and "." ("point") is the current address.
The point of 1203 being that it's a pretty random place in memory that's really unlikely to have code starting there that makes any sense.
-
This snippet deliberately triggers a "Bus error -- Core dumped":
int o1[];
o1 = -3;
*o1;From Dennis_Tapes/dmr/cgd/cg1.c:expr.
@thalia Very interesting program too
did it ever up in anything later or was it more like an experiment? -
A cursed feature of C in 1972: Labels and functions were reassignable (i.e., lvalues)!
For example, this is a clever way to initialize once:
goto init;
init:
ouptr = oubuf;
init = init1;
init1:which is compiled to:
jmp *4120
mov 4136,4144
mov 4122,4120Note the indirect jump and assignment to that address. All gotos used indirect jumps. This apparently would have also worked with functions.
-
R relay@relay.mycrowd.ca shared this topic