Live data from Hacker News

Pointers Are More Abstract Than You Might Expect in C

stefansf.de

201–210 of 267 posts

Re: Pointers Are More Abstract Than You Might Expect in C

#201
post #57

I 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…

> I 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 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 poi…

> 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.

This is also an utter accident, since it depends a great deal on the toolchain. I've worked on compilers and linkers that will put the variables in totally separate parts of the binary (e.g., based on name hash).

Re: Pointers Are More Abstract Than You Might Expect in C

#202
post #187

Earlier quoted context omitted.

Safety is a hardware feature of the Burroughs architecture. C is no less safe there than NEWP.

Sure it is, NEWP only allows for C style unsafely on UNSAFE blocks, clearly tagged by the system administrator as allowed for execution. So not only is lack of safety expressed on the type system, something that C doesn't have, it also allows someone explicitly stating it is ok to risk its execution.

You're assuming that C runs on the Burroughs the way it commonly does on x86, with arbitrary access to all memory within its address space. This is not specified in the C standard, and it's not the case for C on the Burroughs. In particular, since C was not the OS implementation language, but was mainly uaed to port programs from other architectures, the C heap lived entirely within a single memory block and C code could not interfere with other programs. See: https://en.wikipedia.org/wiki/Burroughs_large_systems_descri...

Re: Pointers Are More Abstract Than You Might Expect in C

#203
post #123

Earlier quoted context omitted.

> unlike C, it is not a fundamental part of the lower level semantics I don't think this is an accurate characterization of C, actually. Unless I'm forgetting something, an implementation of C that heap-allocated automatic storage and used continuation passing style could still be conforming. Or in other words, the C standard doesn't specify anything about the memory layout of the stack- the word "stack" isn't even i…

Sure, you can apply a CPS conversion to a C program, but what you would get would actually be a (abstract) function call stack because there is nothing in C that breaks the call stack paradigm (setjmp/longjmp come close but the semantics are carefully defined to avoid breaking the semantics of a call stack; in particular they cannot be used to "restore" stack frames that were previously destroyed by a return statemen…

Okay, but most Scheme code doesn't use call/cc, and even when it does the vast majority of the continuations in use are also "abstract function call stacks."

You said it yourself- a stack is a useful tool for implementing these non-C-like languages. Its presence does not force you to "buy into the C model to some extent."

Re: Pointers Are More Abstract Than You Might Expect in C

#204

Earlier quoted context omitted.

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)…

"That is said a lot, but what are actual desicions that are made to conform to the C model?" Among other things, special instructions to support a function call stack, which is very much specific to the C model. In Lisp the call stack is unnecessary because of the use of continuation passing style, which implies that all function calls are tail calls and mostly requires that everything be heap-allocated (many compile…

> You could also imagine a CPU that does not support general pointer arithmetic or which has some form of built-in array bounds checks, which would all be fine if supporting C were not a requirement.

I am happy to correct you, C does not require that. But also, array bounds checks are not a thing that you can implement physically. There is not necessarily corresponding only a single array length to any given address.

Imagine a virtual machine that just allocates a chunk of ram using malloc to provide virtual memory to the emulated machine. Now add another level of memory management on top.

Or imagime a function tha gets just a subrange of an array, for example to search an element therein. But the actual "array" might be much larger. It might be unclear even to the compiler how large the array is!

Re: Pointers Are More Abstract Than You Might Expect in C

#205
post #3

Earlier quoted context omitted.

> the compiler needs to optimise ... wants to. There fixed that for you ;-) The weird special cases were largely(1) introduced recently by optimizer writers hijacking the standard in order to soften the semantics so that previously illegal optimizations would now be legal, by simply declaring the vast majority of existing C code as "undefined" and up for grabs. Which is why the Linux kernel, among others, has to set…

> The weird special cases were largely(1) introduced recently by optimizer writers hijacking the standard in order to soften the semantics so that previously illegal optimizations would now be legal, by simply declaring the vast majority of existing C code as "undefined" and up for grabs. Citation needed. Signed overflow being undefined behavior was a direct consequence of different hardware representations of number…

Signed overflow was made undefined so that it could do whatever the CPU naturally did, not so that the compiler could delete huge chunks of supposedly dead code.

In the old days, it thus wasn't truly undefined. It was undefined by the language, but you could just look in the CPU documentation to see what would happen. There was some crazy behavior in the old days, but nothing you wouldn't expect from looking at the CPU documentation.

These days, nobody is shipping a C99 or newer compiler for any CPU with weird integers. Everything is twos complement, without padding or trap values. All of that "undefined" stuff should thus be entirely compatible across all modern C compilers.

Re: Pointers Are More Abstract Than You Might Expect in C

#206
post #119

Earlier quoted context omitted.

> faster even than hand-tuned assembly I think you and I are working off different definitions of what that means, as my definition doesn't really allow for a faster implementation (unless there's some really spooky stuff going on in the compiler). I suspect you mean faster than a popular hand tuned implementation.

I don't believe it is possible to hand tune every program to beat a compiler.

How so? Compilers aren't magic, you can - by definition (Assuming the current state machine style (no AI or nuthin') of compilers ) - you can just manually compile it.

Compilers are clever, but humans can also be really clever: They know how to think - You can change the algorithm entirely.

For practical reasons however (Premature optimisation also), trust your compiler.

Re: Pointers Are More Abstract Than You Might Expect in C

#207

> If we step back from the standard and ask our self does it make sense to compare two pointers which are derived from two completely unrelated objects? The answer is probably always no. The one big counterexample I can think of is the difference between memcpy and memmove. The latter is supposed to be able to do arithmetic on memory regions, to see if they overlap. Is this article saying that the standard C implemen…

Memmove is frequently cited as an example of a standard library function that can't be implemented using only standard C. It's incorrect, though: the way to do memmove using standard C is to use malloc to allocate a temporary buffer.

But the whole question is not terribly relevant. When memmove is provided as part of the C implementation it can rely on non-portable platform behaviour just fine. There's no rule that you have to implement libc using only standard C facilities.

Re: Pointers Are More Abstract Than You Might Expect in C

#208
post #37

There'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…

> Comparing the addresses of stack variables is undefined behaviour Can you elaborate? I don't think this is true.

They're from different objects, so it's not meaningful (according to the standard) to compare them. That's what makes it UB.

Re: Pointers Are More Abstract Than You Might Expect in C

#209
post #118
post #4

Earlier 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.

To get the max performance on modern CPU the code has to be cache-aware. It is painful to program for that in C. One often ends up with very complex macros or writing code generators that writes CPU-specific C code. So modern ISA are not designed for C. By such arguments one can claim that CPU are designed for Fortran as it's compilers allows to write fast code with less efforts than in C/C++.

I think it is fair to say that modern ISA are built around a C-speaking world if that's more reasonable.

This may also be especially true - on a technicality: Does the ISA actually specify the exact cache structure of a CPU? If not, then it is definitely reasonable to say that the ISA (if not the whole microarchitecture?) then is designed with C in mind.

Re: Pointers Are More Abstract Than You Might Expect in C

#210
post #208

Earlier quoted context omitted.

> Comparing the addresses of stack variables is undefined behaviour Can you elaborate? I don't think this is true.

They're from different objects, so it's not meaningful (according to the standard) to compare them. That's what makes it UB.

"Not meaningful" and "undefined behavior" have very different meanings.

I agree it's not meaningful, but the standard does define the result of comparing pointers to two unrelated objects with "==", so it's not UB.

Post reply on HN