Live data from Hacker News

Pointers Are More Abstract Than You Might Expect in C

stefansf.de

211–220 of 267 posts

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

#211
post #89

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

> A pointer is just an integer and I can manipulate it like an integer. Except it's not. Not unless you cast it to uintptr_t. Doy. :) Understanding the underlying asm can give you context for what a pointer is, but you can't assume that a pointer is an integer, any more than you can assume 'int' is a machine word in length. There are reasons why C seems so abstruse and abstract. It has to exist on a huge variety of a…

Burroughs does not have a modern C compiler. As far as modern C standards go, the Burroughs architecture does not exist.

The same is true for the rest of the oddball stuff. It's dead now. Nobody is even trying. There is no longer any reason to make the C standard nasty in order to support these systems. The plug should have been pulled on them long ago, when they were well under 1% of the market and declining, but now they are nothing. No standards-conforming compiler supports that old stuff.

Even back at 1%, hurting everybody to support that stuff was not worthwhile. It was a terrible trade-off to make.

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

#212
post #187

Earlier quoted context omitted.

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

It still corrupts their own memory space, which is the whole point of C being unsuitable for any kind of safe software.

C also does not interfere with other programs on its own turf, UNIX.

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

#213
post #141

Earlier quoted context omitted.

C is the common denominator for FFI for OS that happen to be written in straight C, which then mix the C ABI with OS ABI. That is not true in mainframes, Windows (ongoing replacement of Win32 with COM, it is lot of fun to do COM in C, more so UWP), Android (JNI, AIDL), Web (JavaScript/WebAssembly), iOS/macOS (Objective-C runtime), Fuchsia (IDL).

COM and WinRT are still based on the C ABI though. So anything that can do that, can do them - hopefully with more layers on top for convenience sake, of course...

Not quite, COM yes, although it is masochistic to do so without any higher level help.

UWP on the other hand extends COM to support inheritance and value types across calls, and the lowest Microsoft was willing to go on their high performance components was the Windows Runtime C++ Template Library, now replaced by C++/WinRT bindings and updated MIDL compiler.

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

#214

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

Another example of arbitrary pointer comparison I'm familiar with is for resolving lock ordering problems. If I have a big set of locks that I need to take to complete a particular operation, a simple way to prevent deadlocking is to acquire those locks in the order of their pointers. E.g. if I have three locks I need to take, lock_t *a = (lock_t *)0x100; lock_t *b = (lock_t *)0x300; lock_t *c = (lock_t *)0x200; then…

If order of locks is important maybe it's worth considering putting them in an array.

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

#215
post #194

Earlier quoted context omitted.

That’s based on my experience of working with C++ on and off over the last 18 years and reattempting to learn some of the modern pieces of it, as compared to learning and working with Rust over the last 3. I find Rust simpler, more concise, and nearly no footguns. Edit, I didn’t see your Java comment: > I wouldn't say that Rust's safer than Java either. Here’s why it is safer: It has the same set of guarantees about…

Well, that's still personal opinion, even if grounded in experience. My personal opinion is that they have similar complexity, but in general Rust decides to clearly define behaviour as much as possible and fail fast, preferably at compile time. This can be seen when comparing features: memory management is there (supported by the borrow checker), smart pointers are there, references & pointers are there, generics ar…

> that's still personal opinion, even if grounded in experience

I just wanted to make it clear how and why I've formed that opinion.

> unless we want to argue that all bugs are safety issues

Yes, I can definitely be accused of expanding the definition of safety to include all things that cause programs to crash in horrible ways. I look at it as differing levels of guarantees the language makes for you, and Rust makes many more at compile time than others. This adds to the learning curve you mention, is it worth it? Completely depends on if you see those guarantees as valuable.

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

#216
post #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 y…

And how do you implement malloc() in standard C?

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

#217

Earlier quoted context omitted.

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

> I keep seeing people like you claim we should just "fix" undefined behavior Nope. Just don't take undefined behavior to mean "do arbitrary optimizations that dramatically alter the behavior of programs". Let's see what C89 says about undefined behavior: "3.4.3 Undefined behavior --- behavior, upon use of a nonportable or erroneous program construct, of erroneous data, or of indeterminately-valued objects, for which…

Your points are really good. It's a pity that -std=c89 doesn't act as time machine in this respect... would have been useful https://godbolt.org/g/fKfDFq

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

#218

Earlier quoted context omitted.

Obviously Zig's output (courtesy of its LLVM backend) can be expressed and distributed as assembly code, but it's not hand-tuned, it's compiler-generated. Whether the hand-tuned assembly code they used was the fastest out there, I'm not sure. I'd hope so, or they're being misleading. I might get time to re-watch the relevant part of the video - it's around the 21 minutes mark - https://youtu.be/Z4oYSByyRak?t=1292

Andrew explains in the video that the speedup is mostly due to compile-time speed ups and potentially the use of the rorx instruction. It cannot be faster than the fastest assembly because the by definition is the fastest assembly.

> compile-time speed ups and potentially the use of the rorx instruction

Indeed, but the 'compile-time speedups' are a legitimate point in favour of the compiler. If they didn't occur to the assembly programmer, or struck them as too complex to pull off, then the compiler deserves the point.

Have to say I don't follow why the hand-tuned assembly doesn't use the rorx instruction. It's not mentioned in the assembly file, at least, but I thought that was the point? https://www.nayuki.io/page/fast-sha2-hashes-in-x86-assembly

Also, it's neat to see instruction-selection being so significant. Generally might expect cache/branch behaviour to be the kicker.

> It cannot be faster than the fastest assembly

Well, 'fastest assembly' is the domain of so-called 'superoptimisers', and has us pushing at the stubborn bounds of computability.

We were talking about hand-written assembly-code, compared to compiler-generated. Odds are that none of the binaries tested were the optimal assembly.

The only interesting question is whether the hand-tuned assembly code they tested, was the fastest available at the time. If not, the whole demonstration is a straw-man, of course.

Also I don't like that the winning Zig program runs for so much longer. A good benchmark should provide ironclad assurances that no candidate is getting an unfair advantage re. loading/'warm-up'.

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

#219
post #208

Earlier quoted context omitted.

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.

Where? The post cites C11 section 6.5.8 paragraph 5, which seems to disagree with you.

Of course == comparing unrelated pointers is something you need to be able to do, but relational comparisons (including those based on pointer arithmetic) don't seem to be defined anywhere...

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

#220

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

Say you decide to make a video game, and you decide to make a couple of classes for your game objects to inherit from. You make the classes Tool and Weapon. You have just prevented yourself from making the game Clue. The solutions to this tend to be ugly, and your object relations will tend to change over time, often in ways that are difficult to reconcile. Thus, GoF suggests to prefer composition instead of inheritance.
Post reply on HN