I can, however, see an argument that people want a C like language which is a macro assembler. I am lost again when people start asking for a C++ like macro assembler. The features that C++ brings over C are not concepts that exist on any mainstream CPU.
[0] Unless you decide to build a concrete machine (either in bare metal, or as a VM).
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.
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.
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.
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.
"Assembly language for the PC"
https://archive.org/details/assemblylanguage00soch
"TASM Reference"
https://archive.org/details/bitsavers_borlandturemblerVersio...
"Structured Assembler Language For IBM Microcomputers"
https://archive.org/details/structured-assembler-language-fo...
Or just go to MASM documentation, you will find plenty of directives that look like an high level language
https://docs.microsoft.com/en-us/cpp/assembler/masm/directiv...
Put "360 assembler macros" in your search engine and you'll find lots of information.
This is a good place to start: https://www.ibm.com/docs/en/zos/2.1.0?topic=language-macro-i...
C was especially designed to do that! https://stackoverflow.com/questions/53100198/what-is-the-pre...
Um, no. I use a compiler to generate code that would otherwise be very tedious to write. I do not expect it in any way to abstract away the CPU. I do not want it to abstract away the CPU. If I did I would write Java or python. I'm using C++. I am very aware of the CPU. What I'm not aware of is whatever silly transformations the optimizer thinks it can do to my carefully crafted program because I didn't read page 783 of the spec.