Live data from Hacker News

Pointers Are More Abstract Than You Might Expect in C

stefansf.de

61–70 of 267 posts

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

#61

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

Support for unaligned memory accesses in hardware is one. The exceeding majority of variable accesses are through pointers of the correct type, and are therefore to variables that are at least naturally aligned. 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 r…

Afaik, sparcs and many other traditional unix-running cpus does not support unaligned memory access

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

#62
post #39

Note that if the two pointers are passed to a function, and the comparison is done in the function, the results are different: #include void pcmp(int *p, int *q) { printf("%p %p %d\n", (void *)p, (void *)q, p == q); } int main(void) { int a, b; int *p = &a; int *q = &b + 1; printf("%p %p %d\n", (void *)p, (void *)q, p == q); pcmp(p, q); return 0; } That is giving me: 0x7ffebac1483c 0x7ffebac1483c 0 0x7ffebac1483c 0x7…

Yes, I agree. It makes far more sense to make guarantees in a language, that two values are compared using a metric that is invariant. Especially in a language like C, where we expect it to be a very thin abstraction over the machine.

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

#63

This 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;…

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

I've been programming C on and off for 30 years. Rust feels too complex to be a C replacement. C++, yes...

C's paradigm is really about working with memory. Anything that restricts memory access with bound or type checking is going to feel like "not C"...

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

#64

This 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;…

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

> To me Rust is more a C++ replacement than a C replacement.

People make this comparison a lot, but it’s not fair. Rust is far simpler, in terms of number of features of the language, to that of C++. It’s fair to say that Rust is far more expressive than C, but this just represents an initial learning curve that is higher than C, but not as high as C++. The type system is fairly simple in Rust, but it can be used to create very complex things. It does take time to be able to read it, but the guarantees you get from it are very powerful.

> a C replacement should keep the procedural nature of C, with closures perhaps, but not go further in terms of paradigm

Why leave all of the language development of the last ~50 years on the table? Iterators in Rust are amazing, algebraic data types (enums) allow for simple state machine constructs, lifetimes guarantee memory safety, default immutable memory and single mutable owner mean no more concurrent memory modifications. It’s safer than Java, and as fast and memory constrained as C, what’s not to love?

These are amazing features, that allow for amazingly stable programs. To put it succinctly, you get to code once, and then rely on that code for a long time, to focus on building features, not bugs.

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

#65

Earlier quoted context omitted.

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.

That was the argument of C++ advocates in the 90s.

Considering that C doesn't have any good facilities for polymorphism, it's going to continue to be the argument of any language that succeeds C. Unless, that is, that successor language also doesn't have any good facilities for polymorphism, in which case we have Go as a fascinating real-world study in how people will incessantly demand them and deride the language for lacking them (which is saying something, considering that interface{} in Go is already better than pretty much anything one would hack up in C via void pointers or macros).

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

#66

This 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;…

C sort of has this mindset built around it that you're writing portable assembly, except for messy bits like stack frame layout or register allocation. But that doesn't really hold true anymore, and arguably hasn't for decades.

The first obvious issue is that C is specified by an abstract machine that doesn't really correspond to actual hardware. There's no concept of segmented memory, or multiple address spaces in C. Traps don't quite work the way you'd want in C [1]; there's no way to catch a trap that occurs in a specific region of code. Worse, the abstract machine leans on a definition of undefined behavior in such a way that it's painful for programmers but not useful enough to make automatic security permissible. (Unsigned overflow, which is going to be a more common cause of overflows that lead to security vulnerabilities, is well-defined).

However, the more real problem with C is that it is outright missing hardware features that you'd like access to. Things like rotate instructions or wide multiply are easy enough to pattern match, so their lack isn't so devastating. But flag bits--particularly add with carry or checked overflow operations--aren't figured into at all. SIMD vectors have no conception. Returning multiple values via registers. Traps [1]. Coroutines. Multiple address spaces (especially important for GPUs).

[1] Admittedly, the OS is also to blame here: POSIX signals are a really atrocious way to handle machine-generated faults.

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

#67

This 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;…

Some of your complaints could be said about assembly,too, but are you wanting to get rid of that, too? Some of your other complaints are about how processors and other hardware work, not C. In many ways, you are asking for C to be like other languages but then it wouldn't be C and all the advantages it does have. If you get rid of C, you get rid of most of the software your operating system runs on and that begs the…

> if C is so bad, why is everyone using it?

Don't confuse success for correctness, survivorship bias is something to consider here. As others will surely point out, when C was written, there were other languages available at the time that were as fast, but much safer.

In many ways C won, because Unix won, to talk about them separately ignores how important both were to each others success. (Yes, other operating systems adopted C as well, but Unix is it's foundation)

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

#68

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

Support for unaligned memory accesses in hardware is one. The exceeding majority of variable accesses are through pointers of the correct type, and are therefore to variables that are at least naturally aligned. 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 r…

Regarding alignment, I think it's not C that caused aligned reads to be the standard, but rather hardware itself. There isn't anything in C that prevents unaligned reads, is there? Aligned reads are just a consequence of storing data as vectors of a type, which is a very natural and efficient approach. Unless that's somehow a bad idea or prevents other good ideas, the point is moot.

Also caching and page boundaries have nothing to do with C. They are hardware issues (that good C programmers have to deal with, but anyway).

Contemporary Intel x86 haven't had significant problems with unaligned reads for a long time; do a web search for Lemire's post. (I guess there are still restrictions for atomic reads/writes).

I've long wanted to have access to overflow bits or traps on overflow. C certainly isn't in the way of adding them to CPUs, and signed overflow is even undefined in C, which is an opportunity to make them emit a signal or other exeptions. But I agree, C culture did not require hardware vendors to add overflow bits or traps, so maybe that is C's fault.

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

#69
post #3

This 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;…

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

What changes are you thinking of? The only change with respect to undefined behavior I can think of off the top of my head is punning via unions, which C99 changed from undefined behavior to well-defined behavior.

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

#70
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…

> I always thought [] was just syntactic sugar over a regular pointer, but seems like I was wrong.

For another example showing their differences, if a.c has:

    int n[] = { 1 };
And b.c has:

    extern int *n;
    printf("%d\n", *n);
Then running b.c will segfault, whereas if it said extern int n[], it would work as expected (hint: extern int n and printf("%d\n", n) would also work). Arrays degrade to pointers at the drop of a hat, but they're distinct from them.
Post reply on HN