Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

361–370 of 401 posts

Re: Everything I wish I knew when learning C

#361

Earlier quoted context omitted.

Pointers are by far the most insidious thing about C. The problem is that nobody who groks pointers can understand why they had trouble understanding them in the first place. Once you understand, it seems so obvious that you cannot imagine not understanding what a pointer is, but at the beginning, trying to figure out why the compiler won't let you assign a pointer to an array, like `char str[256]; str = "asdf"`, is…

What is so difficult about the concept of a memory address? Is it the C syntax? Asking because I personally have never struggled with this.

> Is it the C syntax?

Pretty sure that this is a big factor, I’m not aware of any recent languages that put type information before and after the variable name. Nowadays there’s always a clear distinction between the variable name and the type annotation.

Re: Everything I wish I knew when learning C

#362

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

It may be strictly UB, but given that any operating system written in C relies on this behavior being well-defined (e.g. the container_of macro widely used in the Linux kernel) you're probably pretty safe. Note that there is sort of an active war between the OS folks, who are probably the main users of pure C nowadays, and the UB nazis among the compiler folks who are mostly worried about efficiently optimizing compl…

The linux kernel compiles with no strict aliasing, so kernel code is unaffected. In userspace this is still dodgy, strict aliasing does affect generated code, and correctness of code that relies on UB this way.

A pragmatic solution would be attributes that allowed declaring that certain pairs of types that are allowed to alias with each other. It would even be better if the C and C++ standards provided facilities for this, although it can be challenging to rigurously fit into the object model.

Re: Everything I wish I knew when learning C

#363
post #132
post #56

Earlier quoted context omitted.

Which is the only possible logical consequence of modifying something that others asked you not. const_cast is there for buggy (or legacy) libraries where const was not specified explicitly, but is implicit in the behavior.

It can happen easily if you don't pay attention with only the standard library. const char *hello = "Hello World !", *world = "World"; char *tmpStr = strstr(hello, world); // IMPLICITE cast from const to non const if(tmpStr) { *tmpStr = 0; // Oupss } C is hard.

so how to safely use strstr then? this is truly a bug hard to find, yet another caveat.

not sure if fuzz testing can help here.

I wonder how many implicit-const-to-non-cost API are in ANSI C and Posix C

Re: Everything I wish I knew when learning C

#364

Earlier quoted context omitted.

Another one corner of the language where arrays actually being arrays is important is multidimensional array access: int arr[5][7]; arr[3][5] = 4; // equivalent to *(*(arr + 3) + 5) = 4; This works because (arr + 3) has type "pointer to int[7]", not "pointer to int". The resulting address computation is (char*)arr + 3 * sizeof(int[7]) + 5 * sizeof(int) == (char*)arr + 26 * sizeof(int) That's also another reason why t…

Really, are multidimensional arrays an important part of the language? The above code looks like it's indexing into an array of pointers. If you want a flat array, make a few inlined helper functions that do the multiplying and adding. Your code will be much cleaner and easier to understand.

Of course multidimensional arrays are an important part of the language, just as the ability to have structs inside structs.

> The above code looks like it's indexing into an array of pointers. If you want a flat array, make a few inlined helper functions that do the multiplying and adding. Your code will be much cleaner and easier to understand.

It is a "flat" array already, not an array of pointers: [0]. No need to write the code that compiler generates for you already.

[0] https://godbolt.org/z/x3cPf3TvT

Re: Everything I wish I knew when learning C

#365
post #360

Earlier quoted context omitted.

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

> 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? The C23 change was mostly to downgrade some of the existing reserved identifiers from "reserved" to "potentially reserved". (It also added some new reserved and potentially reserved identifiers, but they seem reasonable to me.)

I still fail to see any practical difference between these two categories, except that the implementations are recommended to diagnose illegal-in-the-future uses of potentially reserved identifiers but are neither required nor recommended to diagnose actually illegal uses of reserved identifiers. There is also no way to distinguish p.r.i from r.i.

It also means that if an identifier becomes potentially reserved in C23 and reserved in C3X, then compiling a valid C11 program that uses it as C23 will give you a warning, which you can fix and then compile resulting valid C23 program as C3X without any problem; but compiling such a C11 program straight up as C3X will give you no warning and a program with UB.

Seriously, it boggles my mind. Just a) require diagnostics for invalid uses of reserved identifiers starting from C23, b) don't introduce new reserved identifiers, there is already a huge amount of them.

Re: Everything I wish I knew when learning C

#366

Earlier quoted context omitted.

Really, are multidimensional arrays an important part of the language? The above code looks like it's indexing into an array of pointers. If you want a flat array, make a few inlined helper functions that do the multiplying and adding. Your code will be much cleaner and easier to understand.

Of course multidimensional arrays are an important part of the language, just as the ability to have structs inside structs. > The above code looks like it's indexing into an array of pointers. If you want a flat array, make a few inlined helper functions that do the multiplying and adding. Your code will be much cleaner and easier to understand. It is a "flat" array already, not an array of pointers: [0]. No need to…

I am aware that it's flat already.

Re: Everything I wish I knew when learning C

#367
post #200

Earlier quoted context omitted.

In the first example a & b are variables, which can be assigned to each other. In the second a & b are pointers, but b is fixed, so you can not assign a value to it.

They’re not pointers. sizeof a == 4*sizeof(int) , not sizeof(int*) .

They're pointers, just weird ones. The compiler knows it's an array, so it gives the result of the actual amount of space it takes up. If you passed it into a function, and used the sizeof operator in the function, it'd give `sizeof(int *)`. Because sizeof is a compile-time operation, so the compiler still knows that info for your example.

Re: Everything I wish I knew when learning C

#368
post #285

Earlier quoted context omitted.

> " ... is often called the stack." What's wrong about the stack part? It seemed a little odd (and unnecessarily abstract) that the author said "automatic storage" instead of just stack is there a situation where there's automatic storage but no stack?

> is there a situation where there's automatic storage but no stack? Yes. As a trivial example, some C interpreters use a different datastructure instead of a stack.

But the stack refers to the number of calling functions, stacked upon one another too? This is why its always stack, disregard the structure.. cause its a mirror of the program running, and the usual c program uses functions.

Re: Everything I wish I knew when learning C

#369

Earlier quoted context omitted.

If you truly believe so, then can you give an example of input-conditional UB causing unexpected observable behavior, before the input is actually read? This should be impossible, since otherwise the program would have incorrect behavior if a non-UB-producing input is given.

How this might happen is that one branch of your program may have unconditional undefined behavior, which can be detected at the check itself. This would let a compiler elide the entire branch, even side effects that would typically run.

That example doesn't contradict LegionMammal978's point though, if I understood correctly. He's saying that the 'time-travel' wouldn't extend to before checking the conditional.

Re: Everything I wish I knew when learning C

#370
post #288

Earlier quoted context omitted.

You realize these two statements are equivalent, right? > compiling certain source code inputs into bizarre nonsense > winning at compiled-binary-execution-speed benchmarks, giving fewer reasons for people to hand-write assembly code for the sake of speed (assembly code is much harder to read/write and not portable), reducing code size by eliminating unnecessary operations (especially -Os), reordering operations to f…

> If you don't like the complexity of modern, leading-edge optimizing compilers, you are free to build or support a basic compiler that translates C code as literally as possible. Most optimizing compilers can do this already, it's just the -O0 flag.

I tried compiling "int x = 1 / 0;" in both the latest GCC and Clang with -O0 on x86-64 on Godbolt. GCC intuitively preserves the calculation and emits an idiv instruction. Clang goes ahead and does constant folding anyway, and there is no division to be seen. So the oft-repeated advice of using -O0 to try to compile the code as literally as possible in hopes of diagnosing UB or making it behave sanely, is not great advice.
Post reply on HN