I would probably use something like this when hacking on an Apple II with a zero page.
I have also written programs that ran on VMS which dumped memory starting at '0' without getting any segfaults.
I would probably use something like this when hacking on an Apple II with a zero page.
I have also written programs that ran on VMS which dumped memory starting at '0' without getting any segfaults.
Turbo-C used to check the zero location to see if it had changed and would issue a warning if so (in the real mode days).
[0] My other computer is a PDP-11,
It's an old language. Some of the fundamental mistakes were just things that were common at the time and only look so bad in hindsight (e.g. strings, locales, nullable pointers, half the k&r standard library). That doesn't mean we can't and shouldn't do better where we can though.
C and C++ targeting WASM, despite all the security message of how great it is, memory locations inside of the same linear memory segment can still be corrupted, thus providing a way to influence the overall execution logic inside of the sandbox.
At time C was written, swapping in/out of memory measured in literal minutes & when fraction of second of execution time, including swapping in/out of memory, was more than several times the average yearly salary of the day (excluding sneaker net intervention)
Consider how a surgeon would respond if told not to use a scalpel because of the risk of accidental injury when using a sharp tool.
We learn from our mistakes - to which I'd add, sometimes we can afford to make mistakes (home programs) and other times we can't (safety-critical code).
You see the same arguments against static analysis, unit tests, strong type systems, etc. The evidence seems to favor systems which prevent errors over artisinal expertise.
This casts flexibility vs safety as a tradeoff, which it is.
Surgeons are constantly killing people[1], and every time, it turns out it was because the surgeon disabled a known, recommended safety rail, and whenever anyone points out that they should stop disabling the safety rails, they insist that they know how to operate without them, it's those other people that don't. Plus it's sooooo inconvenient for an operation[2] to take five more minutes, they're too good to have to deal with that.
[1] introducing security vulnerabilities
[2] code changeset submission
Honestly, checklists and procedure matter more than most people want to admit.
1] introducing security vulnerabilities
[2] code changeset submission
This is my favorite one
I would agree the same for developers, if similar practices would be enforced everywhere instead of having people calling themselves enginners just because they like how the word sounds.
More quality and process validation, less cowboy programming.
A brick layer doesn't turn into a Construction Engineer, only because they think they know everything about building houses, and have somehow built their own during long weekends.
Likewise a coder out of a bootcamp, isn't someone versed in what actually entails to be a Software Engineer, regarless how cool the title might sound like.
This is significant because the following two snippets of code are not required to be equal in C.
char* c = (char*)(0);
char* d;
memset(&d, 0, sizeof(d));
c == d; // this does not have to be true
That's what the spec says, but are there any computers around anymore where nullptr is not zero? The spec should really go with the times IMHO, old hardware can be supported via platform-specific language extensions.
Yeah that's absolutely fair. I actually can't think of a single platform, embedded or otherwise, old or new, where the null pointer is not address 0.
> Depending on the ``memory model'' in use, 8086-family processors (PC compatibles) may use 16-bit data pointers and 32-bit function pointers, or vice versa.
And it isn't just zero anyway because there's segmentation in play.
[]
*()++
Technically, can only do address "1" with first bit set as a valid, usable address on hardware allowing addressing smaller than 8 bits (standard hardware epsilon factor).So really, address one is literally address 0 + epsilon, where epsilon is minimal addressable bit group, typically 8 bit clean without seg fault.
Although, for standard x86, epsilon size would depend on which ring/boot method level & asm addressing method available (8,16,32,64).
That's also totally valid on WebAssembly btw, address 0 is a regular read/write location.
Yes, I said if you had registers--if you were cheap you could buy your PDP-10 without registers and all the instructions that referenced registers would use core instead.
Since the registers were in effect just 16 words of fast semiconductor memory overlaying the first 16 words of slow core memory you could do anything in them that you could do in regular memory, including running code out of them.
If you had a small loop that did a lot of iterations you could sometimes get a significant speed boost by copying the loop into the registers and running it there.
Originaly using anonymous unions & placing largest bit count variable as first item in union was the context needed to align the "char" correctly -- vs. casting.
Technically, can point at anything in an unaligned manner, just need to align access to machines address boundary to use a "fetch the value of a complete valid memory alignment address". One can hand roll the appropriate shifts/masking to get at the set of bits loaded (which usually let compiler do). Awk and settable end of line marker good way to safely visualize this.
Today you can still work with (say) TI DSP chips that spit complex FFT pipelines results once per cycle and have absolutely no 8-bit hardware addressing or masking abilities as they're lean mean RISC optimised machines for pure 32 or 64 bit floating point operations.
They have C compilers and CHAR_BIT==32 (or 64).
* C preprocessor - it's a text substition operation that can be non standard
* C "the language" - just the syntax folks, no library functions here.
* C "the standard library" - for many of us the K&R stdlib was just a proof of concept example of how to code a library, feel free to ditch it and write up your own string handling, for example.
Which brings us to, say, a multi channel marine seismic processing system that has an IBM PC type design with a custom motherboard that has six TI DSP boards slotted in and you're writing code for the user interface to a real time signal aquisition and processing system and writing onboard code for the numerical processing on the DSP boards.
Now, each board handles a streamer cable, each cable has a number of microphones, an external boomer in the water is triggered and the reflective soundwaves from the ocean floor, and the soundwaves that penetrate the seafloor and later also partially reflected by density change layers, are all captured by the microphones.
You have keyboard+mouse I/O between the real time window manager user interface, shared memory I/O between the PC memory and memory on the DSP cards, analogue soundwaves going to sample ports on the DSP cards, block memory I/O going from the PC to a SEG-9 tape recorder, prepared lines of memory going to a plotter to build an image ...
There's a lot going on.
But, as far as the code compiled for the DSP boards, that mostly handles I/O by linking reaction code to interrupt triggers - when the sampling hardware interrupts to signal another bit of soundwave from microphone[i] is ready, that's stashed in a FiFo queue to be pushed into the DSP handling pipe and to be saved in a raw sample buffer.
When a raw sample buffer is full an interrupt is triggered to take the entire buffer via DMA transfer to be handled PC side by sending it to the SEG-9 tape "of (raw) record", when a processed sample buffer is full an interrupt is triggered for a different type of DMA transfer that takes processed data to display, printer, and to a different SEG-9 track for processed data.
Not much of this is the standard C library, so you can see why you might write your own low level handling.