Live data from Hacker News

“C is how the computer works” is a dangerous mindset for C programmers

words.steveklabnik.com

131–140 of 387 posts

Re: “C is how the computer works” is a dangerous mindset for C programmers

#131

Earlier quoted context omitted.

Not really, assembly language is extremely close to microcode, much much closer than it is to C. C has a whole bunch of baggage like pointer provenance, inability to read uninitialized memory, doesn't understand cache aliasing, etc that don't fit hardware well.

I'm intrigued that you make that claim when as far as I know most microcode is proprietary and not necessarily documented. Also that claim is highly dependent on which cpu and manufacturer you're talking about, if the cpu needed to be updated, etc.

The micro-architectures are reasonably documented enough (e.g. we know what each the execution ports do, that register renaming is a thing) and if you look at e.g. Agner Fog's instruction tables [0] that map macro-instructions onto latencies and port counts, that gives a pretty reasonable picture of what's going on.

[0] https://www.agner.org/optimize/instruction_tables.pdf

Re: “C is how the computer works” is a dangerous mindset for C programmers

#132

Wait until they learn that machine code is not exactly how the computer works either. The hardware is doing things to your code you might not expect.

Right. But machine code is the interface that the hardware provides to the rest of the world, meaning you can ignore that the hardware is doing something different. And in fact, you don't really have access to what the machine is doing. Or maybe you can get at all those virtual renamed registers? I can't, I can just access the architectural registers.

Now if you care about performance, you might not want to ignore the real machine, but it really bis the hardware's job to work like the machine code tells it to. And when it doesn't, that's considered a bug^H^H^H exploit.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#133

Earlier quoted context omitted.

> pointer provenance, inability to read uninitialized memory what do you mean by these two? not sure about the former. as for the latter, of course you can read uninitialized memory, unless you mean something else?

Can you write a well-defined C program that reads uninitialised memory?

Not portably, you could of course use inline assembly in practice, but the normal way of doing it is UB.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#134

Earlier quoted context omitted.

> pointer provenance, inability to read uninitialized memory what do you mean by these two? not sure about the former. as for the latter, of course you can read uninitialized memory, unless you mean something else?

No, reading uninitialized memory in C is UB.

As far as I know (and I could be wrong), reading uninitialized memory in C is not UB, but gives an indeterminate value, which may be either an unspecified value or a trap representation. If it is a trap representation, accessing it is indeed UB, but if all possible values of your memory are valid, e.g. if you have an unpadded integer where every bit representation means something valid, then it is not UB, though it is still an unspecified value which does not even have to be consistent: you could get different values when reading the same uninitialized location twice.

Edit: Some excerpts from the C standard:

6.7.8 Initialization

10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

3.17.2 indeterminate value

either an unspecified value or a trap representation

3.17.3 unspecified value

valid value of the relevant type where this International Standard imposes no requirements on which value is chosen in any instance

6.2.6 Representation of types

6.2.6.1 General

5 Certain object representations need not represent a value of the object type. … Such a representation is called a trap representation.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#135

Earlier quoted context omitted.

This is like saying there's nothing dangerous about guns, because it takes a human to make them dangerous. C is not unsafe if you only write safe code. But humans are fallible, and "just don't write unsafe code" is not a solution.

> This is like saying there's nothing dangerous about guns, because it takes a human to make them dangerous. If you want to go with that analogy, UB is a kin of you intentionally pointing your gun to your foot, taking your time to aim it precisely on your foot, and in spite of all the possible warnings and error messages that are shouted at you... You still decide that yes, what you want to do is to shoot yourself in…

> If you want to go with that analogy, UB is a kin of you intentionally pointing your gun to your foot, taking your time to aim it precisely on your foot, and in spite of all the possible warnings and error messages that are shouted at you…

Yeaaaah not really:

    #include 
    #include 
    #include 

    static char a[128];
    static char b[128];

    int main(int argc, char *argv[]) {
      (void)argc;
      strcpy(a + atoi(argv[1]), "owned.");
      printf("%s\n", b);
      return 0;
    }
compiles with no warning using clang (8), even with -Weverything

And that’s a super easy case, it’s not a use after a dynamic callback somewhere freed a pointer it did not own, or a function 5 levels deep (or worse in a dll) didn’t check its input pointer which only became occasionally null years later.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#136
post #91

Earlier quoted context omitted.

Not really, assembly language is extremely close to microcode, much much closer than it is to C. C has a whole bunch of baggage like pointer provenance, inability to read uninitialized memory, doesn't understand cache aliasing, etc that don't fit hardware well.

>inability to read uninitialized memory printf("%x", *(int*)0x12345678);

Even casting 0x12345678 to int* is undefined behavior

Re: “C is how the computer works” is a dangerous mindset for C programmers

#137

Earlier quoted context omitted.

Can you give an example? The most complicated assembly->microcode examples I can think of are floating-point instructions like FSIN that run CORDIC loops under the hood, and those are still pretty easy to reason about.

Pseudo-code: a = 10; b = 20; c = b + 30; bar = a + b; x = 1; y = 2; z = y + 3; foo = x + y; ... in order to remove dependency stalls might be executed as: b = 20; y = 2; a = 10; x = 1; c = b + 30; z = y + 3; bar = a + b; foo = x + y; This would still be true, even if 'x' and 'a', 'y' and 'b' etc. variables (well, registers) had same name. In that case CPU would just make up new "variables" as required and do the same…

Okay, you're talking about OoO execution here, and you're right that this can be hard to reason about (in terms of stalls/latencies), however that's orthogonal to microcode translation.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#138

Someone told me back in high school that "C is just shorthand for assembly", which I think about a lot. Does anyone else feel that way?

C is not shorthand for assembly, but there are two reasons why it feels like it.

1. You do lots of pointer arithmetic. But I don't think being practiced at pointer arithmetic is important for developing as a programmer. Just learn what it is.

2. Local variables in C exist on the stack, not the heap. But I don't think programming in C is a great way to learn about stacks. Except when you try to return a reference to a local variable from a function, everything feels the same as in other languages.

If you're making a list of languages you want to try out, I wouldn't put C above 5th place. I say this as someone who spent 12 years primarily coding in C.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#139

Earlier quoted context omitted.

Can you give an example? The most complicated assembly->microcode examples I can think of are floating-point instructions like FSIN that run CORDIC loops under the hood, and those are still pretty easy to reason about.

Pseudo-code: a = 10; b = 20; c = b + 30; bar = a + b; x = 1; y = 2; z = y + 3; foo = x + y; ... in order to remove dependency stalls might be executed as: b = 20; y = 2; a = 10; x = 1; c = b + 30; z = y + 3; bar = a + b; foo = x + y; This would still be true, even if 'x' and 'a', 'y' and 'b' etc. variables (well, registers) had same name. In that case CPU would just make up new "variables" as required and do the same…

This has nothing to do with microcode. It doesn't even have anything to do with microops. Reordering instructions (likely register renaming or load-store forwarding here, though the pseudo C code doesn't let me determine) is just part of how the processor retires instructions.

Re: “C is how the computer works” is a dangerous mindset for C programmers

#140

Someone told me back in high school that "C is just shorthand for assembly", which I think about a lot. Does anyone else feel that way?

I think that goes way too far. Assembly is a completely different beast from C and way more complex. There is a lot stuff you can do with assembly that C can’t.

I agree that they are different beasts, but is there anything that assembly can do with data which C can't do? Or are there only control efficiencies which assembly can provide which C can't?
Post reply on HN