3 ms·
C was originally a macro assembler! This new mutation of C is just that, new. I don't mind optimizations as long as it doesn't remove intent, which is usually c
by overgard 5y ago
C was originally a macro assembler! This new mutation of C is just that, new. I don't mind optimizations as long as it doesn't remove intent, which is usually clearly indicated in the source, standards be damned.
- gizmo686 5y agoHow far back to you want to go? There is no definitive start point for C, as it grew fairly organically out of B and began as a living language. However, a reasonable approximation for C 1.0 is The C Programming Language (Kernighan and Ritchie, 1978) [0], commonly known as K&R C. The language they describe is much simpler than modern C. Notably for this discussion, it contains no synchronization mechanisms. There is nothing in that book that suggests C was a macro assembler. On the contrary, its description of C precludes it from being a macro assembler for the reasons I talked about in a parent comment: > Although C matches the capabilities of many computers, it is independent of any particular machine architecture, and so with a little care it is easy to write "portable" programs, that is, programs which can be run without change on a variety of hardware. . It is now routine in our environment that software developed on UNIX is transported to the local Honeywell, IBM and Interdata systems. In fact, the C compilers and runtime support on these four machines are much more compatible than than the supposedly ANSI standard versions of Fortran. > Because the data types and control structures provided by C are supported directly by most existing computers, the runtime library required to implement self-contained programs is tiny. On the PDP-I1, for example, it contains only the routines to do 32-bit multiplication and division and to perform the subroutine entry and exit sequences. Notice the way this paragraph frames the issue. Since the features of C are supported by most machines, it can be implemented with a small runtime library. It does not say that C must use those features directly. In fact, it explicitly anticipates that C could provide some of its primitives in ways other then directly leveraging a corresponding capability of the hardware. The feature here is efficiency and a small runtime. [0] https://1lib.us/book/2660358/b1a4cf https://1lib.us/book/2660358/b1a4cf
- stormbrew 5y agoI'm not sure where you got that idea. C was never ever a macro assembler, and its antecedent language (B[1]) is actually even more abstracted away. C was a slight lowering, not a raising, of hardware abstraction. If C were a macro assembler the following things would be true of it, most likely: - types would have fixed bit sizes (ie. uint32_t would be the norm) - you'd be able to do various 'normal' things for assembly like rotate left and right. - inline assembly would probably be.. you know.. standard instead of something that compiler vendors only started putting in in like the 80s. You might be thinking of the fact that C++ was originally sort of a Macro C (aka Cfront)? [1] Ever wondered why `int` is so fuzzily defined in C? It's because in B there was only one type and it was always word sized. That's also why various things are typed `int` by default if you don't specify.
- Someone 5y agoAnother extremely normal thing assembly allows you to do, but C doesn’t: access carry and overflow flags.
- spc476 5y agoNot all CPUs have carry and overflow flags. For example, MIPS, or SPARC, or the new RISC-V.
- stormbrew 5y agoreally relevant to this discussion, though, the pdp11 did.
- umanwizard 5y agoAnother (modern) example: SIMD instructions.
- overgard 5y ago> I'm not sure where you got that idea History: C was essentially PDP11 macro assembler. There are so many assumptions in C that basically came from the PDP11. C was originally a very utilitarian language to make writing unix easier. That it became massively popular was more of a happy accident.
- stormbrew 5y agoI'm sorry, but this is just a gross mischaracterization of what a "macro assembler" is. I agree it was utilitarian and made to make unix easier and that many of its core assumptions were based on the platform of the pdp11, but it never did in any way resemble a macro assembler as far as I know. And in fact, as gizmo86 pointed out, one of the explicit goals of C in terms of "making unix easier to write" was, afaik, that it would allow the code to be more portable to other architectures, because as the 11 in the name implies, the history that led to the creation of unix was not short on new architectures, and one of the key weaknesses of Multics was, afaik, the fact that it was rigidly written specifically for one specific architecture. By this logic nearly every programming language is just a macro assembler at a certain level of (non-)complexity. All compilers do is translate syntax (macros?) into machine code (assembly?). So, is pascal also a macro assembler? Anyways here is a list of instructions on the pdp11 that you can't directly represent even in the earliest versions of C to my knowledge: ROR ROL SWAB SXT ADC SBC BVC BVS BCS MARK HALT WAIT RESET MTPD MTPI MFPD MFPI MTPS MFPS MFPT CLC CLV CLZ CLN CCC SEC SEV SEZ SEN SCC That's the distinguishing factor of a "compiler" vs. a "macro assembler". A macro assembler is a layer on top of an assembler that still allows you full access to the instruction set and allows control flow that most compilers would consider unsafe. C was never that. It wasn't derived from a language that was that and it didn't, to my knowledge, allow that even on pdp-11 unix. I'd be really happy to see some code from one of the code archives of unix' history that proves me wrong there, though, if you have it.