Live data from Hacker News

Pointers Are More Abstract Than You Might Expect in C

stefansf.de

231–240 of 267 posts

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

#232
post #80

Earlier quoted context omitted.

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

Why would you think that Rust is "far simpler" than C++? Exactly the same concepts (with extras on Rust's side because of the ML-like constructs) must be learned for both, except they're distributed differently on the learning curve. And I wouldn't say that Rust's safer than Java either. Memory access errors are basically non-existant in Java and it has quite robust concurrency primitives and libraries.

You can still get NullPointerExceptions in Java, frequently.

Rust doesn't let you do that, at least not without conciously deciding to use unwrap() everywhere.

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

#233
post #106

Earlier quoted context omitted.

> The same goes for Rust, probably. Well, at least you have the good grace to admit that you haven't used Rust. :P

I've used Rust. It's not simple. For instance, lifetime annotations are ugly and confusing. What a snarky reply from someone who already knows that Rust is not simple. The person you replied to was right, and yet you cast doubt on what he guessed to be true.

The person that response was directed at was attempting to use a mistaken similarity to C++ to paint Rust as a language that is not "sane". You appear to be injecting your own interpretation as to what this subthread is about. :)

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

#234
post #104

Earlier quoted context omitted.

Not sure why the above comment is downvoted. The number of features in C++ isn't the root of the problem with C++. The real problem with C++ is that it both has a lot of features and that all of those features interact in subtle and surprising ways. Even if Rust had as many features as C++ (which it doesn't, not by a long shot; Rust is a medium-sized language like Python (though with a far less forgiving learning cur…

Rust also has features which interact in subtle and surprising ways. Generics and operator traits bumping into the "coherence" rules is my personal pet peave. I doubt any user would have predicted that interaction, and even though the compiler gives a detailed pointer to why, it's cold comfort. Honestly, after hating C++ for years, trying to use Rust made me appreciate more about C++. I wish someone would make a lang…

> even though the compiler gives a detailed pointer to why, it's cold comfort

We'll just have to agree to disagree, because having the compiler watch my back and preemptively guard against unforeseen pitfalls is about the warmest comfort I could ask for. :P

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

#235

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

I've been writing C on and off since 1990, across embedded systems, game consoles, massive SGI supercomputers, and modern kernels.

C is not fading away because of it's portability and low overhead. It has some nasty behaviors, as the original post shows, but you hit those once in a blue moon. The language is not unsound because of it, it just has some warts like any other language.

I don't particularly enjoy writing C, as it's too low level for my liking and I have to write too much code to do basic things (slist_* makes me shudder), but the reason that I have used it is due to its tremendous portability and direct compilation to machine code. That still matters in some places.

In places where memory is precious, or realtime performance precludes things like memory managers, C will continue to thrive, beside languages like Rust which are great for different goals. There's room for both.

C, in my opinion, has stood the test of time on its simplicity, portability, and the ubiquity of the C standard library, tiny as it may be.

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

#236
post #96

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

> C aficionados often claim they love C because it's "simple"(it isn't) That's what they mean, they love C because you can't really do OO with it I do not think C programmers are anti OO. Infact, a lot of C patterns are modeled on OO (struct + function). I think the appeal of C is that you are able to write the fastest implementation any given algorithm, something that just isn't possible in most other languages.

> I think the appeal of C is that you are able to write the fastest implementation any given algorithm, something that just isn't possible in most other languages.

Maybe you can, but lots of the C code I've seen in the last years was pretty inefficient compared to what one would have gotten from a reasonable C++ or Rust implementation:

Examples are inefficient strlen() operations due to the default "string" type, unnecessary copies and allocations of things like strings due to ambiguous ownership, unnecessary null checks to quiet down static analyzers in the absence of non-null references, and extra indirections or allocations in order to work-around missing compile-time generics (besides macros), etc.

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

#237

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.

Ah, unless you're in NT land, which makes lexical scoping of traps very easy: https://github.com/tpn/tracer/blob/0224d94b8d17fe74c39cec285...

        //
        // Verify the guard page is working properly by wrapping an attempt to
        // write to it in a structured exception handler that will catch the
        // access violation trap.
        //
        // N.B. We only do this if we're not actively being debugged, as the
        //      traps get dispatched to the debugger engine first as part of
        //      the "first-pass" handling logic of the kernel.
        //

        if (!IsDebuggerPresent()) {

            CaughtException = FALSE;

            TRY_PROBE_MEMORY{

                *Unusable = 1;

            } CATCH_EXCEPTION_ACCESS_VIOLATION{

                CaughtException = TRUE;

            }

            ASSERT(CaughtException);
        }
The helper #defines: https://github.com/tpn/tracer/blob/0224d94b8d17fe74c39cec285..., e.g.

    #define TRY_TSX __try
    #define TRY_AVX __try
    #define TRY_AVX512 __try
    #define TRY_AVX_ALIGNED __try
    #define TRY_AVX_UNALIGNED __try
    
    #define TRY_SSE42 __try
    #define TRY_SSE42_ALIGNED __try
    #define TRY_SSE42_UNALIGNED __try
    
    #define TRY_PROBE_MEMORY __try
    #define TRY_MAPPED_MEMORY_OP __try
    
    #define CATCH_EXCEPTION_ILLEGAL_INSTRUCTION __except(     \
        GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ? \
            EXCEPTION_EXECUTE_HANDLER :                       \
            EXCEPTION_CONTINUE_SEARCH                         \
        )
    
    #define CATCH_EXCEPTION_ACCESS_VIOLATION __except(     \
        GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? \
            EXCEPTION_EXECUTE_HANDLER :                    \
            EXCEPTION_CONTINUE_SEARCH                      \
        )
    
    #define CATCH_STATUS_IN_PAGE_ERROR __except(     \
        GetExceptionCode() == STATUS_IN_PAGE_ERROR ? \
            EXCEPTION_EXECUTE_HANDLER :              \
            EXCEPTION_CONTINUE_SEARCH                \
        )
    
    #define CATCH_STATUS_IN_PAGE_ERROR_OR_ACCESS_VIOLATION __except( \
        GetExceptionCode() == STATUS_IN_PAGE_ERROR ||                \
        GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?           \
            EXCEPTION_EXECUTE_HANDLER :                              \
            EXCEPTION_CONTINUE_SEARCH                                \
        )

Also allows you to do fun things like this for testing if you can do an AVX512 op (although this is not the supported way of doing things):

    #pragma optimize("", off)
    static
    NOINLINE
    VOID
    CanWeUseAvx512(PBOOLEAN UseAvx512Pointer)
    {
        BOOLEAN UseAvx512 = TRUE;
        TRY_AVX512 {
            ZMMWORD Test1 = _mm512_set1_epi64(1);
            ZMMWORD Test2 = _mm512_add_epi64(Test1, Test1);
            UNREFERENCED_PARAMETER(Test2);
        } CATCH_EXCEPTION_ILLEGAL_INSTRUCTION{
            UseAvx512 = FALSE;
        }
        *UseAvx512Pointer = UseAvx512;
    }
    #pragma optimize("", on)
https://github.com/tpn/tracer/blob/0224d94b8d17fe74c39cec285...

The structured exception handling protocol used by NT is really quite elegant.

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

#238
post #233

Earlier quoted context omitted.

I've used Rust. It's not simple. For instance, lifetime annotations are ugly and confusing. What a snarky reply from someone who already knows that Rust is not simple. The person you replied to was right, and yet you cast doubt on what he guessed to be true.

The person that response was directed at was attempting to use a mistaken similarity to C++ to paint Rust as a language that is not "sane". You appear to be injecting your own interpretation as to what this subthread is about. :)

I assumed you were contradicting this quote:

> This just means that the Rust language does not have the feature of being simple.

I really don't know what it means for a language to be sane, so it didn't make any sense to me that you were replying to that part. My bad.

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

#239

Earlier quoted context omitted.

The only thing I ask of any C-replacement languages is that they make it possible to describe ABIs, message layouts, and on-disk formats in detail. C historically does that well enough, though not really all that well (e.g., bitfields and enums have issues, and struct packing is not always easy to get right). There is a lot of value to this! The ability to mix object code from multiple languages (FFI) is critical, an…

I won't do this justice, so I'll point you to the Rust book on this subject: https://doc.rust-lang.org/book/second-edition/ch19-01-unsafe... In short, at the moment, if you want a stable ABI, you must export an un_mangled C interface. This is easy enough. One of my favorite sites is this for FFI stuff: http://jakegoulding.com/rust-ffi-omnibus/ It covers a bunch of languages, and suggests techniques for overcoming any…

I wasn't criticizing Rust, and I'm aware of what you linked. The point I was making is that this sort of functionality is a sine qua non for C-replacement languages. That Rust has it is to its credit, and one reason that I think it is a very good C-replacement language.

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

#240
post #234

Earlier quoted context omitted.

Rust also has features which interact in subtle and surprising ways. Generics and operator traits bumping into the "coherence" rules is my personal pet peave. I doubt any user would have predicted that interaction, and even though the compiler gives a detailed pointer to why, it's cold comfort. Honestly, after hating C++ for years, trying to use Rust made me appreciate more about C++. I wish someone would make a lang…

> even though the compiler gives a detailed pointer to why, it's cold comfort We'll just have to agree to disagree, because having the compiler watch my back and preemptively guard against unforeseen pitfalls is about the warmest comfort I could ask for. :P

Generics and operator traits ought to be orthogonal and composable. Would you still be comforted if the compiler didn't let you mix for loops and arithmetic in one function? I mean, even if it gave you a detailed error message...
Post reply on HN