Okay so basically if it’s not ASM then it’s a high level scripting language and you’re a webshit soydev. The only exceptions to this are autism languages that have nothing going for them outside of how “functional” they are. For more information visit /g/ on 4chan.
@methyltheobromine@Moon@newt wait for someone to explain how you are dumb for not using C++ and exceptions actually make sense and the syntax is not insane
The program itself is still compiled down to a format that directly mentions registers, stack pointers, memory loads ... it's still running those actual instructions. The kernel just interrupts it after a given number of cycles and the memory map isn't real; it's virtual pages (which still has special instructions in hardware that the kernel calls).
Exactly. Did you read Writing Software That Actually Works Considered Harmful? The site it runs on doesn’t display the text if you have JavaScript enabled to filter securitylets.
The key point is that C superficially looks like a linear sequence of instructioms operating on a single, uniform, linearly addressable memory, and while thay was true on PDP-11, on modern CPUs of the big kind (like AMD Ryzen or ARM Cortex-A) that's not the case.
@piggo@pony@methyltheobromine@Moon@newt These CPUs are out-of-order superscalar - they reorder instructions, and execute multiple insns in parallel, as long as all the dependencies on results of previous instructions are satisfied.
Moreover, they have hierarchies of caches, and multiple cores, each core sering the memory differently than other cores.
@piggo@methyltheobromine@Moon@newt but it isn’t really that close to the hardware? Unless you think about the operating system as hardware, but you have no idea where things really are (and you don’t necessarily know how the pages align so that’s also fun).
@Moon@pony@methyltheobromine@piggo@newt that being said, with assembly you have a more direct access to the primotives used to manage this implicit concurrency - fences, cache flush instructions, atomic instructions, etc. - in C these are usually packed into __vendor_extensions or wrapped by high-level concurrency libs like pthreads.
@Moon@pony@methyltheobromine@piggo@newt On most CPUs I know about, the instruction set tries to give you the same illusion of linear execution and memory. There were atrempts to go lower - there were the VLIW, and more recently The Mill CPU. The former failed miserably outside of GPU / DSP land. The latter, to my knowledge, hasn't produced a single physical CPU yet.
@Moon@pony@methyltheobromine@piggo@newt Also, I think LLVM IR, or some other static-single-assignment format, is a better model of how the CPU sees the program, but technically it's not closer to hardware than assembly.
@jeff >your program is being interpreted by the kernel Sorry, but I'd just like to interject for a moment.
Kernels don't typically interpret C programs - what they do instead is schedule the process and at certain time periods, load all the registers back from the stack, jmp execution to the right instruction in .data and after a set period, dump all the registers to stack and then jmp execution elsewhere.
If a kernel does this thousands of times a second, it looks like the computer is doing a bunch of things at once, although only one thing is happening at a time.
>your machine isn't a pdp-11 This is true simply because the CPU arch is different, you're not allowed to program the microcode (a free microcode was developed for the PDP-11 for example), it's not feasible to write anything but small functions in straight machine code like it could be done on the PDP-11 and machine code instructions are rarely executed directly on the metal anymore.
For AMD64 CPUs, when machine code instructions are read by the instruction decoder, the instructions are usually converted into micro-ops instead of being executed directly and then those micro-ops are passed to the execution engine that does lots of dark magic like instruction reordering, simultaneous execution and speculative execution. As a result, even if you write in assembly, the actual instructions that get executed are very different (in most cases the behavior is the same, but not always - there are bugs in the execution engine for example).
>C isn't close to hardware C isn't close to the hardware simply because the language allows you to construct structures and mechanisms that have no equivalent machine code instructions - but the compiler is very good at generating all the instructions required to carry out your will.
With gcc at high optimization levels, it's rare that the output looks anything but vaguely similar to the input - gcc's optimizer is so good that it detects when it's most performant to wrap or unwrap loops, add padding to make a function larger, but run faster, when to turn division or modulo into faster multiplication instructions, when to use the fastest equivalent out of addition, LEA or MUL instructions for multiplication, optimize alignment and much, much more.
Pretty much, with C, gcc can do whatever it damn well pleases as long as the operations executed in the end are the same, or in the case of undefined behavior, it can do anything it wants, including making demons fly out of your nose.
>pointers and structs go directly to memory down to the bit level That isn't the case anymore sadly.
Memory Management Units, address remapping, caching and the buffering of RAM I/O means that memory isn't controllable to the bit level anymore.
For example, if the CPU detects that a chunk of memory is being used a lot, that memory may be loaded into the cache and further reads and writes will be mapped to those bytes in the cache - without the original memory address or pointer addresses changing on the programming side at all.
The CPU at a later time may flush the cache and schedule for the cache contents to be written back to the main memory, replacing the old dirty memory (yes, there are a lot of very confusing bugs that result from reading stale cache or RAM).
Memory sadly isn't bit, or even byte addressable anymore, with DRAM, as any reads and writes go into an I/O buffer and reads and writes are handled as blocks (although it's possible for a block to be sent that only changes one bit). SRAM is still bit addressable, but it's expensive to get a large amount of that, but depending on implementation, the interface may only address bytes.
RAM I/O is handled by a memory controller built into the CPU and don't forget that DRAM is pretty much a bunch of leaky buckets and must be refreshed many times a second (16 is typical for DDR2 if I remember correctly), thankfully most memory controllers have a single command to trigger memory refresh.
Additionally, any time DRAM is read. the charge in read cells are lost and such blocks are written back to avoid data loss.
One of the reasons why C can be very fast is because pointers and structs map direct to the simulated address space and memory map with minimal overhead, so it's possible to arrange structs in alignment efficient ways, for loops in cache efficient ways and do pointer arithmetic to quickly make calculations, for example the length of data to copy; memcpy(sneed, feed, chuck-feed); would very efficiently map to approximately (ignoring caller-save to avoid complexity); mov [sneed],%rdi //0th argument mov [feed],%rsi //1st argument sub chuck,feed,%rdx //2nd argument call mempy
Meanwhile, good luck turning a method call into 4 instructions in your typical OOP language.
Pretty much, C maps very well to existing abstractions, that map to the hardware, so it runs very fast, despite no longer being close to the hardware.
>if you use a compiler like Tiny C Compiler without optimizations stuff maps close to cpu instructions Even TCC does some optimizations for divisions etc, meaning there is no direct mapping to CPU instructions, although the output is pretty similar.
I could keep going, but it'll probably be better for me to answer specific wonderings.
Modern hardware has so many abstractions that C will never be aware of. You can't choose if your memory allocation should be in RAM, L1, L2, L3, etc as one example.
@feld my issue was that I didn't understand the context for the original statement. no programming language has access to that, but it's fair to say that C is not "close to hardware" even if nothing is.
I will defend it, it runs like hell when you need it to. It will bite you like that shark. Till you bleed enough time to just understand. That’s all, my stuff is rock solid.
Dunno why there’s this war with C/C++ it’s not possible to accomplish some tasks unless you want to resort to assembly.