Not quite. (char *) 0 is the null pointer. The null pointer is not necessarily a binary all-zero. On some compilers in x86, the null pointer intentionally points to something which will cause a crash when written to.
but technically speaking the pointer with a constant zero assigned to it _is_ a null pointer (which can be implemented as whatever bit pattern), independent of the preprocessor macro.
> This is writing sizeof(char) (== 1 almost everywhere)
1 everywhere. sizeof's unit is "how many chars". For instance there was a cray machine that could only access 64bit words. sizeof(char) is still 1, with 64bit chars.
> zero to address zero. It is not using a NULL macro or other predefined symbol.
sizeof is an operator in C, and does not need parenthesis any more than pointer operator *. It is true that programmers frequently think of it as a function and use parenthesis.
To begin with, sizeof has two syntaxes: the first, which is the one you seem to refer to, is simply
sizeof expression
where expression involves variables and constants, not types. The second is
sizeof (type)
where the parentheses are mandatory.
Then, even in the first syntax, even if sizeof is listed among the operators, even if it doesn't look any different from "pointer operator ", nonetheless it has strange priority rules. For example
sizeof (T) *x
If it was a regular prefix operator obeying priority and right-to-left evaluation, this would mean: dereference x, cast it to T, and return its size. Instead the C standard forces the compiler to interpret it as: take the size of type T and multiply it by x.
Hilariously I've been down voted, even though you absolutely need sizeof (char) because it's a type. Given char x; sizeof x is fine. I know sizeof is an operator. I've been using C for 40 years.
Guess can be taken as a shortened explaination of what a programming language committee is tasked with making happen. Likely why Lisp so successful/useful.
-----
unless initial property is start of dynamic operation, in which case, holding almost anywhere begins at the first operation after the start of the dynamic operation. process / lambda / epsilon calculi is just symbolic math. address 0 static, everything else dynamic.
per math, dimension N is static, to be able to "change things up" in dimension N, need to to be almost everywhere higher than dimension n. Edge cases are weird in any dimension. Guess why logicians just do the equivalent of C's !0
(cast classic logic) A=1
(cast boolean logic) B=0
C statement !(!B == A) hold everywhere and almost everywhere depends on how read C spec to interpret A & B.
Regarding your PS, I used Borland's Turbo C++ 1.0, and I think you've forgotten that memory models existed. Honestly, that's a good nightmare to forget.
I hated that about DOS, real-mode and BC++. After about 6-8 months of that misery, installing linux and learning to write C code with GCC was the best thing that ever happened to me. I felt like an animal being released from a cage and into the wild.
In those days MS-DOS, Linux was barely usable, when Linux became usable Windows 95 was already around, without those limitations.
My first kernel was 1.0.9 released alongside Slackware 2.0, offering initial support for IDE CD-ROM drives and experimental support for ELF files, by the way.
It doesn't have to be the NULL macro, which is correctly defined as plain 0.
The literal 0 is treated specially, so this could indeed be one of those 'turns into a weird bit pattern NULL pointers', if such a thing existed in the wild anymore.
But you're correct in that there probably haven't been any since the turn of the century or whenever the last Univac mainframes got turned off.
Apparently according to the c-faqs link elsethread
execl takes a variable-length, null-pointer-terminated list of character pointer arguments, and is correctly called like this:
execl("/bin/sh", "sh", "-c", "date", (char *)0);
Due to ececl being a variadic function it can not take advantage of a prototype to instruct the compiler that one of its arguments needs to be treated as a pointer context.