Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

141–150 of 401 posts

Re: Everything I wish I knew when learning C

#141
post #125
post #74

> Everything I wish I knew when learning C By far my biggest regret is that the learning materials I was exposed to (web pages, textbooks, lectures, professors, etc.) did not mention or emphasize how insidious undefined behavior is. Two of the worst C and C++ debugging experiences I had followed this template: Some coworker asked me why their function was crashing, I edit their function and it sometimes crashes or do…

> how insidious undefined behavior is. Indeed. UB in C doesn't mean "and then the program goes off the rails", it means that the entire program execution was meaningless, and no part of the toolchain is obligated to give any guarantees whatsoever if the program is ever executed , from the very first instruction. A UB-having program could time-travel back to the start of the universe, delete it, and replace the entire…

I agree with the factual things that you said (e.g. "entire program execution was meaningless"). Some stuff was hyperbolic ("time-travel back to the start of the universe, delete it").

> [compilers] will make transformations to the program whose effects could manifest before the UB-having code executes [...] It's monumentally rude to us poor programmers who have bugs in our programs.

The first statement is factually true, but I can provide a justification for the second statement which is an opinion.

Consider this code:

    void foo(int x, int y) {
        printf("sum %d", x + y);
        printf("quotient %d", x / y);
    }
We know that foo(0, 0) will cause undefined behavior because it performs division by zero. Integer division is a slow operation, and under the rules of C, it has no side effects. An optimizing compiler may choose to move the division operation earlier so that the processor can do other useful work while the division is running in the background. For example, the compiler can move the expression x / y above the first printf(), which would totally be legal. But then, the behavior is that the program would appear to crash before the sum and first printf() were executed. UB time travel is real, and that's why it's important to follow the rules, not just make conclusions based on observed behavior.

https://blog.regehr.org/archives/232

Re: Everything I wish I knew when learning C

#143
post #125

Earlier quoted context omitted.

> how insidious undefined behavior is. Indeed. UB in C doesn't mean "and then the program goes off the rails", it means that the entire program execution was meaningless, and no part of the toolchain is obligated to give any guarantees whatsoever if the program is ever executed , from the very first instruction. A UB-having program could time-travel back to the start of the universe, delete it, and replace the entire…

Personally, I've found that some of the optimizations cause undefined behavior, which is so much worse. You can write perfectly good, strict C that does not cause undefined behavior, then one pass of optimization and another together can CAUSE undefined behavior. When I learned this, if it was and is correct, I felt that one could be betrayed by the compiler.

Optimizations themselves (except for perhaps -ffast-math) can't cause undefined behavior: the undefined behavior was already there. They can just change the program from behaving expectedly to behaving unexpectedly. The problem is that so many snippets, which have historically been obvious or even idiomatic, contain UB that has almost never resulted in unexpected behavior. Modern optimizing compilers have only been catching up to these in recent years.

Re: Everything I wish I knew when learning C

#144

I find this article very strange, perhaps because I started using 'c' so long ago. To the bullet points: (1) In general, 'c' is always 'c' at the command line, regardless of the platform. (2) yes, there are options and build tools, but cc my_program.c -o my_program works fine. I have a very hard time figuring out how to compile/run java. (3) hard to see how this has anything to do with 'C', vs any other compiled lang…

It's largely the same, aside perhaps from not shipping with the java compiler by default:

  * install java (includes compiler/runtime): `sudo apt install default-jre`
  * compile: `javac MyProgram.java`
  * run:     `java MyProgram`

Re: Everything I wish I knew when learning C

#145
post #65

I would add to this: 1. Visual Studio debugger is really, really good and you should use it to step through your program (or equivalent IDE based workflow). 2. Learn to compile your code with memory safeguards and use the tooling around them. Specific depends on the platform. On POSIX address sanitizer is good I hear. On Windows you can use the debug CRT and gflags to instrument your binary really well.

People should be using IDEs with modern debuggers anyways.

Being able to step through your code one line at time and instantly see the values of all your variables is going to be FAR more effective than adding a bunch of print statements, no matter what language you're using.

It always blows my mind to hear about how many engineers don't know how to use their IDE's debugger and don't know what a breakpoint is.

Re: Everything I wish I knew when learning C

#146

" ... is often called the stack." " integers are cursed" These statements and a few others made me uncomfortable. They imply, to me, that the author has too little knowledge of computer internals to be programming in C. C does a wonderful job of looking like a high level language but it was designed to do low level stuff. There is an implicit assumption, to my mind, that the user has a deeper understanding of what is…

>C does a wonderful job of looking like a high level language but it was designed to do low level stuff. There is an implicit assumption, to my mind, that the user has a deeper understanding of what is behind the "curtain" that is created by the compiler.

Lots of people say this, indeed several comments here talk about learning assembly before C being beneficial.

I actually think this is not true, today. In its original incarnation C may have mapped closely to instructions, but the details of e.g. x86 are IMO neither necessary nor particularly useful knowledge. Knowing what memory is like and how stuff is laid out is enough.

C is not just a super-thin layer to the bare metal. By "integers are cursed," I mean exactly that: C integers are cursed. The arithmetic behaviours that standard C defines for integers are error-prone and in many cases undefined. C is a layer and it has its own behaviour, it doesn't just expose your CPU.

Re: Everything I wish I knew when learning C

#147

Earlier quoted context omitted.

I would be surprised if C guarantees those x and y to have same offsets Plus you cant cast and dereference one type's pointer to the other. That would be UB

Modulo any padding rules, I would be surprised if C didn't store them in the same offsets, the compatible-type specification[1] and equality operator[2] (also see footnote 109) would make implementation much harder if you tried to do it any other way. The way to work around that of course, and to make sure that no matter what , the parent/child objects are compatible to the parent-only level is to do something like:…

Even if the fields are stored in the same offsets, there are modern optimisations that rely on "strict aliasing" and that would cause issues (unless the workaround you described is used).

Re: Everything I wish I knew when learning C

#148

" ... is often called the stack." " integers are cursed" These statements and a few others made me uncomfortable. They imply, to me, that the author has too little knowledge of computer internals to be programming in C. C does a wonderful job of looking like a high level language but it was designed to do low level stuff. There is an implicit assumption, to my mind, that the user has a deeper understanding of what is…

Year 1 in my university, they started with electron, I was impressed. All to way to diode and how logic gate was made. And then digital circuit design, and you got your one|two's complement from here.

Re: Everything I wish I knew when learning C

#149
The older I got, the more I realized you seem to be heavily disadvantaged by not having some rudimentary understanding of assembly when using C.

When you do have such an understanding, some small details, like declaring stack variables at the top of functions in ANSI C, become obvious.

Re: Everything I wish I knew when learning C

#150
post #125
post #74

> Everything I wish I knew when learning C By far my biggest regret is that the learning materials I was exposed to (web pages, textbooks, lectures, professors, etc.) did not mention or emphasize how insidious undefined behavior is. Two of the worst C and C++ debugging experiences I had followed this template: Some coworker asked me why their function was crashing, I edit their function and it sometimes crashes or do…

> how insidious undefined behavior is. Indeed. UB in C doesn't mean "and then the program goes off the rails", it means that the entire program execution was meaningless, and no part of the toolchain is obligated to give any guarantees whatsoever if the program is ever executed , from the very first instruction. A UB-having program could time-travel back to the start of the universe, delete it, and replace the entire…

> Indeed. UB in C doesn't mean "and then the program goes off the rails", it means that the entire program execution was meaningless, and no part of the toolchain is obligated to give any guarantees whatsoever if the program is ever executed, from the very first instruction.

This is the greatest sin modern compiler folks committed to abuse C. C as the language never says the compiler can change the code arbitrarily due to an UB statement. It is undefined. Most UB code in C, while not fully defined, has an obvious part of semantics that every one understands. For example, an integer overflow, while not defined on what should be the final value, it is understood that it is an operation of updating a value. It is definitely not, e.g., an assertion on the operand because UB can't happen.

Think about our natural language, which is full of undefined sentences. For example, "I'll lasso the moon for you". A compiler, which is a listener's brain, may not fully understand the sentence and it is perfectly fine to ignore the sentence. But if we interpret an undefined sentence as a license to misinterpret the entire conversation, then no one would dare to speak.

As computing goes beyond arithmetic and the program grows in complexity, I personally believe some amount of fuzziness is the key. This current narrow view from the compiler folks (and somehow gets accepted at large) is really, IMO, a setback in the computing evolution.

Post reply on HN