Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

201–210 of 401 posts

Re: Everything I wish I knew when learning C

#201
post #27

Earlier quoted context omitted.

... which is why I never understood why this is the convention rather than int* x, y. Does somebody know?

Because now you've got an int pointer and an int. The star associates with the right, not left. I prefer to use the variant you described though, because it feels more natural to associate the pointer with the type itself. As far as I know, the only pitfall is in the multiple declaration thing so I just don't use it. IMO, it's also more readable in this case: int *get_int(void); int* get_int(void); The second one mor…

Multiple declaration is generally frowned upon, because you declare the variables without immediately setting them to something.

If you always set new variables in the same statement you declare them, then you don't use multiple declarations, which means there is no ambiguity putting the * by the type name.

So convention wins out for convention's sake. And that's the entire point of convention in the first place: to sidestep the ugly warts of a decades-old language design.

Re: Everything I wish I knew when learning C

#202
The reason you use specific sizes for types (int8, int16, uint16, etc) is so you know how to read/write them when you move your data between platforms.

x86 is little endian. ARM apparently can be configured to be either.

In real code there should be readXXX and writeXXX functions that read/write data from disk/network and do the byte swapping in there.

You could also just convert everything to JSON, but you're trading space for complexity/time.

Re: Everything I wish I knew when learning C

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

I'm not sure that's a productive way to think about UB. The "weirdness" happens because the compiler is deducing things from false premises. For example, 1. Null pointers must never be dereferenced. 2. This pointer is dereferenced. 3. Therefore, it is not null. 4. If a pointer is provably non-null, the result of `if(p)` is true. 5. Therefore, the conditional can be removed. There are definitely situations where many…

This is the problem; every compiler outcome is a series of small logic inferences that are each justifiable by language definition, the program's structure, and the target hardware. The nasal demons are emergent behavior.

It'd be one thing if programs hitting UB just vanished in a puff of smoke without a trace, but they don't. They can keep on spazzing out literally forever and do I/O, spewing garbage to the outside world. UB cannot be contained even to the process at that point. I personally find that offensive and rude that tools get away with being so garbage that they can't even promise to help you crash and diagnose your own problems. One mistake and you invite the wrath of God!

Re: Everything I wish I knew when learning C

#204
post #141

Earlier quoted context omitted.

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…

> Integer division is a slow operation, and under the rules of C, it has no side effects. Then C isn't following this rule - crashing is a pretty major side effect.

The basic deal is that in the presence of undefined behavior, there are no rules about what the program should do.

So if you as a compiler writer see: we can do this optimization and cause no problems _except_ if there's division by zero, which is UB, then you can just do it anyway without checking.

Re: Everything I wish I knew when learning C

#205
post #159
post #54

Earlier quoted context omitted.

Not at all! a is int; &a is pointer to int; x is pointer to int; *x in again int.

Gotcha, so it's kind of like: int (*(x = &(a))); i i p p i // i means int, p means pointer

I prefer to think of it as

    (int *) x = &(a);
     i   p  p   a i // a means address       
    
Which is why I prefer to write

    int* x = &a;
"integer pointer" named "x" set to address of integer "a".

---

As a sibling comment pointed out, this is ambiguous when using multiple declaration:

    int* foo, bar;
The above statement declares an "integer pointer" foo and an "integer" bar. It can be unambiguously rewritten as:

    int bar, *foo;
But multiple declaration sucks anyway! It's widely accepted good practice to set (instantiate) your variables in the same statement that you declare them. Otherwise your program might start reading whatever data was lying around on the stack (the current value of bar) or worse: whatever random memory address it refers to (the current value of foo).

Re: Everything I wish I knew when learning C

#206
post #151

Earlier quoted context omitted.

There have been more than a few compiler bugs that have introduced UB and then that was subsequently optimized, leading to very incorrect program behavior.

A compiler bug is a compiler bug, UB or not. You might as well just say "There have been more than a few compiler bugs, leading to very incorrect program behavior."

The whole thread is about how UB is not like other kinds of bugs. Having a compiler optimization erroneously introduce a UB operation means that downstream the program can be radically altered in ways (as discussed in thread) that don't happen in systems without the notion of a UB.

While it's technically true that any compiler bug (in any system) introduces bizarre, incorrect behavior into a program, UB just supercharges the things that can go wrong due to downstream optimizations. And incidentally, makes things much, much harder to diagnose.

Re: Everything I wish I knew when learning C

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

I'm not sure that's a productive way to think about UB. The "weirdness" happens because the compiler is deducing things from false premises. For example, 1. Null pointers must never be dereferenced. 2. This pointer is dereferenced. 3. Therefore, it is not null. 4. If a pointer is provably non-null, the result of `if(p)` is true. 5. Therefore, the conditional can be removed. There are definitely situations where many…

> There are definitely situations where many interacting rules and assumptions produce deeply weird, emergent behavior

The problem is how due to other optimisations (mainly inlining) the emergent misbehaviour can occur in a seemingly unrelated part of the program. This can the inference chain very difficult, as you have to trace paths through the entire execution of the program.

The issue occurs for other types of data corruption, it’s why NPE are so disliked, but UB’s blast radius is both larger and less reliable.

Re: Everything I wish I knew when learning C

#208

I like it, but the array details are a little bit off. An actual array does have a known size, that's why when given a real array `sizeof` can give the size of the array itself rather than the size of a pointer. There's no particular reason why C doesn't allow you to assign one array to another of the same length, it's largely just an arbitrary restriction. As you noted, it already has to be able to do this when assi…

Another weird property about C arrays is that &arr == arr. The reference of an array is the pointer to the first element, which is what `arr` itself decays to. If arr was a pointer, &arr != arr.

I think it is clearer to say that arr == &arr[0] but your mileage may vary.

Re: Everything I wish I knew when learning C

#209

I was born in '74 so the last generation to start with C and go to other, higher-level, languages like Python or JavaScript. Going in this direction was natural. I was amazed by all the magic the higher-level languages offered. Going the other direction is a bit more difficult apparently. "What do you mean it does not do that?". Interesting perspective indeed!

I was born in the late 80s and C was my first language, in a community college intro to programming class.

Re: Everything I wish I knew when learning C

#210
post #93

Earlier quoted context omitted.

Why the hell "potentially reserved" was introduced? How is it different from simply "reserved" in practice except for the fact such things can be missing? How do you even use a "potentially reserved" entity reliably? Write your own implementation for platforms where such an entity is not provided, and then conditionally not link it on the platforms where it actually is provided? Is the latter even possible? Also, app…

From https://www.open-std.org/JTC1/sc22/wg14/www/docs/n2625.pdf : > The goal of the future language and library reservations is to alert C programmers of the potential for future standards to use a given identifier as a keyword, macro, or entity with external linkage so that WG14 can add features with less fear of conflict with identifiers in user’s code. However, the mechanism by which this is accomplished is overly…

So... instead of mandating implementations to warn about (re)defining a reserved identifier, they introduce another class of "not yet reserved indentifiers" and advise implementations to warn about defining such identifiers in the user code — even though it's completely legal, — until the moment the implementation itself actually uses/defines such an identifier at which point warning about such redefinition in the user code — now illegal and UB — is no longer necessary or advised.

Am I completely misreading this or is this actually insane? Besides, there is already a huge swath of reserved identifiers in C, why do they feel the need to make an even larger chunk of names unavailable to the programmers?

Post reply on HN