> The reason I believe C is and always will be important is that it stands in a class of its own as a mostly portable assembler language, offering similar levels of freedom.

When your computer is a PDP-11, otherwise it is a high level systems language like any other.

Less controversially, when you write C, you write for a virtual machine described by the C spec, not your actual hardware.

Your C optimizer is emulating that VM when performing symbolic execution, and the compiler backend is cross-compiling from it. It's an abstract hardware that doesn't have signed overflow, has a hidden extra bit for every byte of memory that says whether it's initialized or not, etc.

Assembly-level languages let you write your own calling conventions, arrange the stack how you want, and don't make padding bytes in structs cursed.

These are all such nonsensical misinterpretations of what people mean when they say C is "low level". You absolutely don't write C for the C abstract machine, because the C spec says nothing about performance, whereas performance is one of the primary reasons people write C.

The existence of undefined behaviour isn't proof that there is a C "virtual machine" that code is being run on. Undefined behaviour is a relaxation of requirements on the compiler. The C abstract machine doesn't not have signed overflow, rather it allows the compiler to do what it likes when signed overflow is encountered. This is originally a concession to portability, since the common saying is not that C is close to assembly, but rather that it is "portable" assembler. It is kept around because it benefits performance, which is again one of the primary reasons people write C.

I'm not trying to prove a novel concept, just explain how the C spec thinks about C:

> The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.

This belief that C targets the hardware directly makes C devs frustrated that UB seems like an intentional trap added by compilers that refuse to "just" do what the target CPU does.

The reality is that front-end/back-end split in compilers gave us the machine from the C spec as its own optimization target with its own semantics.

Before C got formalised in this form, it wasn't very portable beyond PDP. C was too opinionated and bloated for 8-bit computers. It wouldn't assume 8-bit bytes (because PDP-11 didn't have them), but it did assume linear memory (even though most 16-bit CPUs didn't have it). All those "checking wetness of water... wet" checks in ./configure used to have a purpose!

Originally C didn't count as an assembly any more than asm.js does today. C was too abstract to let programmers choose addressing modes and use flags back when these mattered (e.g. you could mark a variable as `register`, but not specifically as an A register on 68K). C was too high level for tricks like self-modifying code (pretty standard practice where performance mattered until I-cache and OoO killed it).

C is now a portable assembly more because CPUs that didn't fit C's model have died out (VLIW) or remained non-standard specialized targets (SIMT).

C performance exists thanks to UB, and the value optimising compilers extract out of it, during the 8 and 16 bit home computers days any average Assembly developer could write better code than C compiler were able to spit out.

And also because it doesn't get in your way of doing exactly what you want to do.

If that was true then the optimizers wouldn't need to exist in the first place.

Compared to the alternatives.

It gets very frustrating to communicate at this level.

The alternatives outside Bell Labs were just as capable.

I don't think compilers allowing trash through is a good thing.

That's an opinion, another one would be that the flexibility allowed by undefined behavior is one of C's strengths at the same time. Strength/weakness are often two sides of the same coin. Which is why these discussions get a bit circular.

Have you ever seen the error steamroller? https://github.com/mattdiamond/fuckitjs

ON ERROR RESUME NEXT rears its ugly head again

> Less controversially, when you write C, you write for a virtual machine described by the C spec, not your actual hardware.

Isn't this true for most higher level languages as well? C++ for instance builds on top of C and many languages call into and out of C based libraries. Go might be slightly different as it is interacting with slightly less C code (especially if you avoid CGO).

> When your computer is a PDP-11, otherwise it is a high level systems language like any other.

Describing C as "high-level" seems like deliberate abuse of the term. The virtual machine abstraction doesn't imply any benefits to the developer.

> Describing C as "high-level" seems like deliberate abuse of the term

Honestly it doesn't really matter. High level and low level are relative to each-other (and machine language), and nothing changes based on what label you use.

Best thing to do is shrug and say "ok".

That's a curious remark, although I guess it doesn't look high level from the eyes of someone looking at programming languages today.

C has always been classed as a high level language since its inception. That term's meaning has shifted though. When C was created, it wasn't assembly (middle) or directly writing CPU op codes in binary/hex (low level).

Spend 90 days writing nothing but assembly language and then tell me that you believe C is a low level language.

I don't see much difference. What is C suppose to express that assembly cannot? What is assembly suppose to express that C cannot? Does this conversation matter to begin with?

You did not spend 90 days writing assembly language. I doubt you even spent 1 day.

For one, C has types and type-checking.

Neither does pretending C is a macro Assembler.

While C was adapted to the PDP-11, this was adding byte-level memory access. Otherwise I do no think there is anything in C specific to the PDP-11, or what would this be?

What makes C low-level is that it can work directly with the representation of objects in memory. This has nothing to do with CPU features, but with direct interoperability with other components of a system. And this is what C can do better than any other language: solve problems by being a part of a more complex system.

The post-increment and post-decrement operators mapped directly onto PDP-11 CPU addressing modes.

The integral promotion rules come directly from the PDP-11 CPU instruction set.

If I recall correctly so does the float->double promotions.

CPUs started adapting to C semantics around the mid-80's. CPU designers would profile C generated code and change to be able to more efficiently run it.

Thanks. I guess the integral promotion is related to byte-addressing. If you have bytes but can not directly do arithmetic on them, promoting them to word size seems natural.

Can you elaborate? C constructs generally map to one or a few assembly instructions at most. You can easily look at C and predict the generated assembly. This is in contrast to other compiled languages, like Go, that inject instructions for garbage collection and other runtime features.

See my list of languages on a sibling thread, same applies to those, nothing special about C there.

Yeah, people keep repeating that like a broken record lately, it smells like Rust to me.

No one is claiming it was built for today's processors, just that it puts less obstacles between you and the hardware than almost any other language. Assembler and Forth being the two I'm familiar with.

Because people keep repeating the urban myth of portable assembler and being the very first systems programming language.

One of the very first systems programming languages was JOVIAL, from 1958. C's inventors were still finalising their studies.

I don't know how to phrase this to reach through, but you're barking up the entirely wrong tree. It's not about the CPU, it's about the level of freedom afforded by the language; how close to hardware it allows you to go, how few hoops you have to jump trough to get there.

The other approach, taken by Rust (and to some degree C++), is to nail everything to the floor and force the programmer to express a solution in a specific format that's easier to verify and make guarantees about. Which is fine.

Both approaches have their appeal, which is best depends on context.

Which is again nothing special about C, other languages offer similar capabilities, I have provided a list in a sibling comment.

Keep waiting for the examples where they can't do what ISO C allows for, and if the example uses compiler extensions to the ISO C, I also feel within the right to use extensions to those languages on the counter example.

C is a relatively low level language, but it is not assembly language.

The difference is clear. Assembly language programs specify sequences of CPU instructions. C programs specify runtime behavior.

Which other popular language more accurately represents a random access machine of fixed word length?

I don't know, Ada, Modula-2, Object Pascal, PL/I, NEWP, PL.8, D, Zig, Mesa, ATS,....

But then again, you booby trapped the question with popular language.

Many of those languages do not have pointers - which are fundamental to how modern instruction sets work.

Yes they do, point an example from that group, and I will gladly prove you wrong.

Well sounds like you are confident and we are going to get into a semantic argument about what qualifies as a pointer.

So which of these languages do you think is a better representation of hardware and not a PDP-11?

Better representation of the hardware?

None of them, you use Assembly if you want the better representation of hardware.

Yes, I am quite confident, because I have been dispelling the C myth of the true and only systems programming language since the 1990's.

So then your comment about C being an outdated PDP-11 must be equally true of other languages. So it says nothing.

Not really, some of those languages predate the very existence of C and PDP-11.

[deleted]

If a language is unpopular, people won't want to work for you and you'll run into poor support. Rewriting a library may take months of dev time, whereas C has an infinite number of libraries to work with and examples to look at.

wears math hat

C does not have an infinite number of libraries and examples. The number of libraries and examples C has is quite large, and there are an infinite number of theoretically possible libraries and examples, but the number of libraries and examples that exist are finite.

The infinite is a convenient abstraction of the finite.

Moving goalposts regarding systems programming languages features, some on the group predate C by a decade.

Being old doesn't mean anyone knows the language. I mean if the language predates C significantly and nobody uses is then there's probably a really good for it. The goalposts aren't moving they're just missing the shot

Popularity isn't a measure of quality. Never has been and certainly not in the case of programming languages.

There is unpopular - and then there is can I get a working toolchain for modern OS that’s not emulated.

Still not a measure of quality.

Are we having a discussion about the greatest language of all time? What’s your context here.

C lacks sympathy with nearly all additions to hardware capabilities since the late 80s. And it's only with the addition of atomics that it earns the qualification of "nearly". The only thing that makes it appear as lower level than other languages is the lack of high-level abstraction capabilities, not any special affinity for the hardware.

For one, would expect that a low level language wouldn't be so completely worthless at bit twiddling. Another thing, if C is so low level, why can't I define a new calling convention optimized for my use case? Why doesn't C have a rich library for working with SIMD types that has been ubiquitous in processors for 25 years?

Like, say I have a data structure that is four bits wide (consisting of a couple of flags or something) and I want to make an array of them and access them randomly. What help do I get from C to do this? C says "fuck you".

Pick an appropriate base type (uintN_t) for a bitset, make an array of those (K * N/4) and write a couple inline functions or macros to set and clear those bits.

Only if you don't know C.

Otherwise is says, do whatever you feel like.

It puts less obstacles in the way of dealing with hardware than almost any other language for sure.

What's standardized was never as important in C land, at least traditionally, which I guess partly explains why it's trailing so far behind. But the stability of the language is also one of its features.

It also has pointers which are absent from most languages but essential to instruction sets.

Lots of languages since the 1950's have pointers.

simd doesnt make much sense as a standard feature/library for a general purpose language. If you're doing simd its because you're doing something particular for a particular machine and you want to leverage platform specific instructions, so thats why intrinsics (or hell, even externally linked blobs written in asm) is the way to go and C supports that just fine.

But sure, if all youre doing is dot products I guess you can write a standard function that will work on most simd platforms, but who cares, use a linalg library instead.

None, but that'a not what computers are. C assumes that in a few places, e.g. variadic functions, and those are the worst parts of the language.

> but that'a not what computers are

Which language more accurately represents hardware then?

C++ for one - it has atomics with well defined memory barriers, and guarentees for what happens around them.

The real answer is obviously Assembly - pick a random instruction from any random modern CPU and I'd wager there's a 95% chance it's something you can't express in C at all. If the goal is to model hardware (it's not), it's doing a terrible job.

C has the same atomics and concurrency model as C++.

C++ better represents the machine?

Assembly language from the hardware vendor.

isn't it translated to microcode before being executed?

Depends on the hardware design.

[flagged]

bro just quoted a chatbot