Basically you have no guarantee where the pointer q is pointing to. Some compiler/static code analyzer will yell at you with this code.
isn't it guaranteed that is points sizeof(int) bytes higher than the address of b? Whether something useful is behind that address is another question
Pointers Are More Abstract Than You Might Expect in C
51–60 of 267 posts
Re: Pointers Are More Abstract Than You Might Expect in C
#52Earlier quoted context omitted.
The following is purely my opinion. Rust might have gone too far the other way. Yes it strives to be a modern language, with a lot of functional programming features and "OOP" done right (aka no inheritance, simply method polymorphism). To me Rust is more a C++ replacement than a C replacement. A replacement for C should try to be as simple as possible while fixing C weak typing mess with strong typing for instance,…
> OOP" done right (aka no inheritance, simply method polymorphism). Why do you consider inheritance a bad feature of OOP?
OOP can become spaghetti very quickly. Especially as people mistakenly allow children to modify parent memory directly, protected non-final fields in Java. Once that happens and as the inheritance higherarchy gets deep, understanding what a field actually is at any point becomes very difficult.
Interface and trait inheritance at least removes one piece of confusion by only allowing functions to be inherited, which makes code much easier to reason about.
Re: Pointers Are More Abstract Than You Might Expect in C
#53This scratches the surface of why I hope C slowly fades away as the default low-level language. C sounds simple when you look through K&R C. C lets you feel like you understand the stack, ALU and memory. A pointer is just an integer and I can manipulate it like an integer. But the reality is filled with a staggering number of weird special cases that exist because memory doesn't work like a simple flat address space;…
> memory doesn't work like a simple flat address space Can you expand on that? I thought that modern (non-segmented) memory does work like a simple flat address space, at least from the perspective of userspace programs. Isn't all the weirdness only a result of compiler optimisations?
Re: Pointers Are More Abstract Than You Might Expect in C
#54This scratches the surface of why I hope C slowly fades away as the default low-level language. C sounds simple when you look through K&R C. C lets you feel like you understand the stack, ALU and memory. A pointer is just an integer and I can manipulate it like an integer. But the reality is filled with a staggering number of weird special cases that exist because memory doesn't work like a simple flat address space;…
If you get rid of C, you get rid of most of the software your operating system runs on and that begs the question you need to ask yourself: if C is so bad, why is everyone using it?
Re: Pointers Are More Abstract Than You Might Expect in C
#55There's nothing surprising in the first example. Comparing the addresses of stack variables is undefined behaviour. The second one is more interesting: extern int _start[]; extern int _end[]; void foo(void) { for (int *i = _start; i != _end; ++i) { /* ... */ } } GCC optimized "i != _end" into "true". The kernel guys fixed this by turning "_start" and "_end" into "extern int*". I always thought [] was just syntactic s…
Actually, the headline article tells us that it optimized it to true. That affected some of my code from years ago, too; and another fix is to keep _start and instead of having another array called _end have an external size_t giving the number of elements of start and loop while i!=_start+count . In fairness to the compiler people there shouldn't really be anything surprising in the second example, either. There are…
If you set "_start" and "_end" to addresses of different objects, then you're invoking undefined behaviour and all bets are off. But this should be perfectly valid IMO:
extern char* _start;
extern char* _end;
void foo() {
for (char* c = start; c != end; c++) ...
}
int main(int, char**) {
char buf[128];
_start = &buf[0];
_end = &buf[128];
foo();
}
Right?Re: Pointers Are More Abstract Than You Might Expect in C
#56Earlier quoted context omitted.
But as you know, CPU ISAs are designed for C programs and compilers are optimized for C programs. So everything, even new languages like Rust, have to buy into C's model to some extent. Truly getting out from under C's shadow is going to be very difficult. Maybe better languages are a first step on that path but they are only a small step.
That is said a lot, but what are actual desicions that are made to conform to the C model? What would be good ideas in CPU design that aren't made since they are not compatible with C? (I get it that CPUs have to support some common paradigms and use cases. For example, virtual memory / process isolation, maybe branch prediction things, or support for calling conventions. However, I don't think that is specific to C)…
But a very small handful of systems/procedures make unaligned accesses through type-punned pointers. Rather than just crash on these programs, processors will perform multiple memory accesses and stitch the results back together in hardware (worst case behavior: accesses that cross page boundaries). So there's extra hardware to perform this extra state tracking and detect the unaligned accesses in the first place.
Hardware doesn't just get turned off for conforming programs. Its there consuming energy and giving off heat on all of them.
Edit/addendum Here's another example: What should hardware do on integer overflow? There are several options, including signed-saturation, unsigned saturation, unsigned wraparound, and trap. The semantics of C are such that most hardware just picks 'unsigned wraparound' and makes programs eat the consequences. If you're very lucky then you also get 'an overflow bit, that gets clobbered on the next instruction'.
One way to think about this problem might be to ask the question, "What hardware features would reduce the runtime cost of instrumenting programs with the various sanitizers that are becoming available?"
Re: Pointers Are More Abstract Than You Might Expect in C
#57I like the behavior of the compiler here. There is no guarantee that a and b are next to each other in memory. That's why the comparison fails, the alternative makes is runtime/compiler/optimization level dependent which would be a total mess. As usual with those C bashing articles you won't run into trouble if you don't try very hard to write contrived code. I mean, the moment you see: int *q = &b + 1; on your scree…
Yes, there is no guarantee that they are next to each other, but in this case they happen to be next to each other, and according to the spec as quoted in the article, two pointers are equal if:
> [...] one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space
Note that it says "happens to" immediately follow, not "is guaranteed to" immediately follow.
This are pointers to ints, not arrays of ints, but that should not matter because as quoted in the article:
> For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
I don't see any way to read these as not requiring the pointers to compare as equal if the compiler happens to put a and b adjacent in memory in the right order and with no padding between them, other than resorting to something ridiculous like claiming that "follow" or "immediately" follow are not defined in the spec and so one object occupying that very next available address after another does not necessarily "immediately follow". This seems to be what the gcc developers went with to declare this is not a bug.
Also, note that if you move the "int a, b" to outside main, so a and b are on the heap instead of on the stack, then gcc does find that the pointers are equal.
Re: Pointers Are More Abstract Than You Might Expect in C
#58the comparison at the start is nonsense - there is no specification for the ordering or location of stack variables. by taking the address of these variables, you could see that they actually are the same value, and so intuitively you’d think they might be the same, but a different compiler might put them in different locations. or they may be elided entirely through optimisation. it’s far safer to fail the equality…
Surely the point of writing an if-block testing the equality of the pointers is precisely because the code isn’t assuming that they are the same - but maybe it has something it wants to do if it finds itself running somewhere where they are. Writing code which assumed those pointers were equivalent would be bad, but this code doesn’t do that. Instead, it looks like the compiler assumes that the pointers won’t be the…
Re: Pointers Are More Abstract Than You Might Expect in C
#59Earlier quoted context omitted.
The following is purely my opinion. Rust might have gone too far the other way. Yes it strives to be a modern language, with a lot of functional programming features and "OOP" done right (aka no inheritance, simply method polymorphism). To me Rust is more a C++ replacement than a C replacement. A replacement for C should try to be as simple as possible while fixing C weak typing mess with strong typing for instance,…
You don't need to use any polymorphism (generics or traits) in Rust. You can use it as a pure structs and functions language like C (especially if you're not using the standard library). The argument in favour of at least some polymorphism is that it helps to minimise highly repetitive code that would be avoided in C through aliasing, type punning or other pointer conversion.
Of cause you can find a sane subset of c++ / rust that most comfortable with. But once your project accept c++ / rust, nothing can stop them using the other "features" of the language.
Trying to enforce code style drain lots of energy from the project. Maybe a good linter can help......
Re: Pointers Are More Abstract Than You Might Expect in C
#60Earlier quoted context omitted.
But as you know, CPU ISAs are designed for C programs and compilers are optimized for C programs. So everything, even new languages like Rust, have to buy into C's model to some extent. Truly getting out from under C's shadow is going to be very difficult. Maybe better languages are a first step on that path but they are only a small step.
That is said a lot, but what are actual desicions that are made to conform to the C model? What would be good ideas in CPU design that aren't made since they are not compatible with C? (I get it that CPUs have to support some common paradigms and use cases. For example, virtual memory / process isolation, maybe branch prediction things, or support for calling conventions. However, I don't think that is specific to C)…
The very concept of "the stack" implies a C-style evaluation model.
Having a single address space for both code and data mainly just gives an opportunity for optimisation to fail.
Everything-is-mutable gives a lot of opportunity for optimisation to fail. The compiler wants the program in SSA form, it register-allocates to a bunch of reused names, only for the CPU microcode to figure out which uses of those names can actually be used to mean separate physical registers.
Arguably the failure of VLIW (in particular Itanium) was because of C: those processors could (maybe) have run more constrained languages very fast, but it was difficult to compile C to run fast on them.