Live data from Hacker News

Everything I wish I knew when learning C

tmewett.com

341–350 of 401 posts

Re: Everything I wish I knew when learning C

#341
post #309
post #106

> C has no environment which smooths out platform or OS differences Not true - C has little environment, not no environment. For example, fopen("/path/file.txt", "r") is the same on Linux and Windows. For example, uint32_t is guaranteed to be 32 bits wide, unlike plain int. > Each source file is compiled to a .o object file Is this a convention that compilers follow, or are intermediate object files required by the C…

fopen will/should fail on windows with the unix path syntax. The reason it's indeterminate is because some stdc lib vendors will do path translation on Windows, some won't. I believe cygwin does (because it's by definition a unix-on-windows), but I'm pretty sure the normal stdclib vendors on windows do not. I'm almost positive that MacOS (before MacOS X) will fail with unix path separators, since path separators are…

It will work on Windows, since it inherits the behavior from MS-DOS. It's the shell on Windows (or MS-DOS) where it fails since the shell uses '/' to designate options, so when MS-DOS gained subdirectories (2.0) it used '\' as the file separator on the shell. The "kernel" will accept both. There even used to be an undefined (or underdefined) function in MS-DOS to switch the option character.

Re: Everything I wish I knew when learning C

#342
post #308

Earlier quoted context omitted.

Then you are wrong, since we're already talking about arrays of sizes known at compile time. Indeed, otherwise we would also need to remember the size in the runtime.

IIRC this is valid in C99: void foo(size_t n) { int arr[n]; … }

How do you think it works? Does the compiler generate some kind of stack alloc?

Stupid question: Does that mean a huge value for 'n' can cause stack overflow at runtime? I recall that threads normally get a fixed size stack size, e.g., 1MB.

Re: Everything I wish I knew when learning C

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

...Why is the compiler reordering so much? Look. I get it, clever compilers (I guess) make everyone happy, but are absolute garbage for facilitating program understanding. I wonder if we are shooting ourselves in the foot with all this invisible optimization.

People like fast code.

Re: Everything I wish I knew when learning C

#344
post #276

Earlier quoted context omitted.

It doesn't matter how it knows. The standard permits it to do that. The compiler authors will not accept your bug report.

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.

Re: Everything I wish I knew when learning C

#345

Earlier quoted context omitted.

> It is definitely not, e.g., an assertion on the operand because UB can't happen. C specification says a program is ill-formed if any UB happens. So yes, the spec does say that compilers are allowed to assume UB doesn't happen. After all, a program with UB is ill-formed and therefore shouldn't exist! I think you're conflating "unspecified behavior" and "undefined behavior" - the two have different meanings in the sp…

> So yes, the spec does say that compilers are allowed to assume UB doesn't happen. They are allowed to do so, but in practice this choice is not helpful.

On the contrary, it is quite helpful–it is how C optimizers reason.

Re: Everything I wish I knew when learning C

#346
post #288
post #278

Earlier quoted context omitted.

Miscompilations are rarer and less annoying in compilers that do not have the design behaviour of compiling certain source code inputs into bizarre nonsense that bears no particular relation to those inputs.

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.

Re: Everything I wish I knew when learning C

#347
post #282

Earlier quoted context omitted.

> The deal is known and fair. It often isn't. C is often falsely advertised as a cross-platform assembly language, that will compile to the assembly that the author would expect. Some writers may be used to pre-standardization compilers that are much less hostile than modern GCC/Clang.

> C is often [correctly, but misleadingly] advertised as a cross-platform assembly language, that will compile to the assembly that the author would expect. Because that's what it is. What they don't tell you is that the most heavily-developed two (or more) compilers for it (which you might otherwise assume meant the two best compilers), are malware[0] that actively seek out excuses to inject security vulnerabilities…

Socialism is when the government does something I don't like, and Reflections on Trusting Trust is when my compiler does something I don't like. The paper has nothing to do with how optimizing compilers work. Compiling TCC with GCC is not going to suddenly make it into a super-optimizing UB-exploiting behemoth.

Re: Everything I wish I knew when learning C

#348
post #7

This looks decent, but I'm (highly) opposed to recommending `strncpy()` as a fix for `strcpy()` lacking bounds-checking. That's not what it's for, it's weird and should be considered as obosolete as `gets()` in my opinion. If available, it's much better to do the `snprintf()` way as I mentioned in a comment last week, i.e. replace `strcpy(dest, src)` with `snprintf(dst, sizeof dst, "%s", src)` and always remember tha…

snprintf is pretty slow, partly because it returns things people typically don't want.

Re: Everything I wish I knew when learning C

#349

Earlier quoted context omitted.

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…

The C and C++ (and D) compilers I wrote do not attempt to take advantage of UB. What you got with UB is what you expected to get - a seg fault with a null dereference, and wraparound 2's complement arithmetic on overflow. I suppose I think in terms of "what would a reasonable person expect to happen with this use of UB" and do that. This probably derives, again, from my experience designing flight critical aircraft p…

This is the right approach IMO, but sadly the issue is that not all C compilers work like that even if they could (e.g. they target the same CPU) so even if one compiler guarantees they wont introduce bugs from an overzealous interpretation of UB, unless you are planning to never use any other compiler you'll still be subject to said interpretations.

And if you do decide that sticking to a single compiler is best then might as well switch to a different and more comfortable language.

Re: Everything I wish I knew when learning C

#350

Earlier quoted context omitted.

The C and C++ (and D) compilers I wrote do not attempt to take advantage of UB. What you got with UB is what you expected to get - a seg fault with a null dereference, and wraparound 2's complement arithmetic on overflow. I suppose I think in terms of "what would a reasonable person expect to happen with this use of UB" and do that. This probably derives, again, from my experience designing flight critical aircraft p…

I think this is a core part of the problem; if the default for everything was to not take advantage of UB things would be better - and we're fast enough that we shouldn't NEED all these optimizations except in the most critical code; perhaps. You should need something like gcc --emit-nasal-daemons to get the optimizations that can hide UB, or at least horrible warnings that "code that looks like it checks for null ha…

AFAIK GCC does have switches to control optimizations, the issues begin when you want to use something other than GCC, otherwise you're just locking yourself to a single compiler - and at that point might as well switch to a more comfortable language.
Post reply on HN