Live data from Hacker News

There is no 'printf'

netmeister.org

121–130 of 158 posts

Re: There is no 'printf'

#121

Earlier quoted context omitted.

> C compilers will typically have an escape hatch for envs like deeply embedded systems and kernels like gcc's -ffreestanding and -fno-builtin that says "but for real though, don't assume std lib functions exist or you know what they are based on the function's name". GCC requires standard library functions even on freestanding environments! It will still emit calls to those functions in certain circumstances. https:…

This comment isn't meant to disagree with what you said but is more like a related ramble. At least in C++, memcpy is special because it can be used to reinterpret bits of one object as another (in C you can use a union, and as of C++20 you can use the std::bit_cast function but it either just calls memcpy or it still needs its own magic) double d = 1.0; // type punning with union, allowed in C but not C++ union { do…

What a pain, right? Why can't they just let us do what they know we want to do? It's such an absurd situation.

We have double precision floating point numbers. Sometimes we want to look at the bits. Sometimes we want to modify those bits. Would it kill them to let us cast the thing? I will never understand this.

Re: There is no 'printf'

#122

Imagine somebody thought omitting the return statement and doing whatever the compiler likes is a good feature to have.

Is is the opposite. The original C compiler produced instructions very closely to the higher level language.

As such, it produces code based on what you tell it, no more, no less. If you don't tell it what value to return from a subroutine, it does not generate the code to. It is quite common to have a function that does not return a value.

The case shown here is not a case of the compiler doing 'what it likes', but the compiler not emitting any code for it. The fact that the return value from the function called last is still in the register used to return values when the function returns is simply a result of no code that touches that register in between.

As someone else pointed out, if you look at the code generated for a PDP-11 all the quirky things like, pointers with pre or post increment operators make much more sense as they emit instructions that do just that.

Re: There is no 'printf'

#123

Earlier quoted context omitted.

Because it's surprising and breaks our expectations. The author of this article clearly expected a call to printf to be present in the generated code. > all I care about is that those characters are written to the standard output stream when I run the program Sometimes people care about a lot more. Such as the ability to hook into a specific function or ensuring the compiler doesn't generate calls to certain function…

That's exactly why we have specifications and standards - so that you don't have to guess and build mental models on flimsy assumptions, and know exactly what to expect.

The standard leaves so much stuff undefined or implementation defined there's no way to fully understand what's going on anyway. The only mental model you can form is of the very limited non-existent abstract machine, anything else you have to guess or go to great pains to avoid. It just isn't very useful to think in those terms, so many intuitions just aren't possible. Turns the language into this huge minefield.

I've given up on that. Standards don't compile code so they don't really matter in the end. I'm interested in what my compilers do and the code they generate. I've found I can just tell them to define the formerly undefined behavior, significantly improving the language as a result. No strict aliasing, forcing signed integers to wrap around as you'd expect them to, etc.

Re: There is no 'printf'

#124
post #122

Imagine somebody thought omitting the return statement and doing whatever the compiler likes is a good feature to have.

Is is the opposite. The original C compiler produced instructions very closely to the higher level language. As such, it produces code based on what you tell it, no more, no less. If you don't tell it what value to return from a subroutine, it does not generate the code to. It is quite common to have a function that does not return a value. The case shown here is not a case of the compiler doing 'what it likes', but…

Is it undefined behavior?

Re: There is no 'printf'

#125

There is 'printf'. It's just that printf (and the rest of the standard library) is technically as much a part of the C language as the language grammar itself, and C compilers are welcome to use innate knowledge of those functions for optimizations. The other place you typically see this is calls to functions like memcpy/memset being elided to inline vector ops or CISC copies, or on simpler systems, large manual zero…

> C compilers will typically have an escape hatch for envs like deeply embedded systems and kernels like gcc's -ffreestanding and -fno-builtin that says "but for real though, don't assume std lib functions exist or you know what they are based on the function's name". GCC requires standard library functions even on freestanding environments! It will still emit calls to those functions in certain circumstances. https:…

The requirements for memcpy, memmove, memset and memcmp stem from the fact that statements like "char arr[100] = {0};" or "struct somestruct some_a = some_b;" cause implicit memsets and memcpys, in cases where it can't be handled within less instructions. These functions are required by the freestanding part of the C standard, too, anyway.

Re: There is no 'printf'

#126
post #2

Huh, this is pretty great; I've always fussily used fputs() when I'm just printing static strings, and apparently I don't need to bother, since the compiler will just do it for me.

It doesn't hurt to use (f)puts anyway when you intend to print a static string. This way you avoid extra overhead when using compilers that don't do this or building with flags that disable this optimization, as well as just clarify your intent.

Re: There is no 'printf'

#127

Earlier quoted context omitted.

What do you feel the difference is between "directly issuing system calls" and "some inline assembly"?

Using some system interrupts vs calling some driver.

To issue system interrupts (afaik) it would have to use inline assembly. Or non-inline assembly, linked to the rest of the library.

C doesn't have an 'int' (call interrupt) primitive.

So the answer to your question is yes.

Re: There is no 'printf'

#128
post #23

[off topic] I always wondered how '%n' is used in production code.

https://stackoverflow.com/questions/3401156/what-is-the-use-...

Those answers were so frustrating to read. The question is explicitly asking "Why does this exist? When would you need it?" and yet most of the answers are "This is what it does." (sometimes with a few snide RTFMs thrown in for good measure).

Re: There is no 'printf'

#129

Earlier quoted context omitted.

> AFAIK clang will usually just treat a signed overflow as an unsigned overflow when optimizing as it simplifies things. This was a bit of a surprise to me; I thought that Clang could use the presence of signed overflow to infer bounds, like when it "breaks" naïve overflow checks. I didn't know about the treat-signed-as-unsigned behavior you described. If that's what clang is doing, that's pretty neat! Quite a bit of…

Treat-signed-as-unsigned is what you get "by default" with a two's complement representation of integers, if you just use ADD/SUB opcodes regardless of the type (i.e. the cheapest/fastest way to do it).

Right, but I had thought that clang would have done something involving deducing the bounds of n, which could be used to avoid overflow in later optimizations.

Now that I think about it, though, they key there is "could" - overflow could be avoided by deducing bounds, but if said deduction can't occur then what you describe sounds like the most natural action to take as long as there aren't other issues.

Re: There is no 'printf'

#130

Earlier quoted context omitted.

I would say that is a bug. More than 22 years ago, ISO C introduced this requirement for a reason. The reason was almost certainly the desire to fix that issue for as many C programs as possible, and that there was no intent that there be an exceptions for C programs that happen to request C90 compatibility in their accompanying Makefile. An indeterminate termination status causes real problems like, oh, if those pro…

But there aren't a lot of good reasons to compile with C90 or older these days (for portability you can just restrict yourself to the portable subset). I suspect the flag is there to support old unmaintained programs and it makes sense not to change their behaviour (because nobody is going to fix bugs in them), as long as it is not a big burden on the compiler. In fact, think of old K&R C instead of C90. I wouldn't b…

> aren't a lot of good reasons to compile with C90

Sure there are, like:

- Project doesn't want mixed declarations and statements creeping into the code base

- Project doesn't want want variable-length arrays creeping into the code base.

- Project doesn't want new footguns in preprocessing.

- Project hates mixtures of // and /.../ comments.

I think the Linux kernel is still using C90 (with GNU extensions).

> tools that relied on propagating the result of the last operation executed into main.

In all the situations in which the compiler has enough information to indicate the insert of a "return 0", it could emit a diagnostic (if it is in C90 mode).

   foo.c:17: warning: main returns without a value [-std=c90, -Wmain-return]
The user is alerted to this and can look at the code and decide whether it's just missing a "return last_operation();" or whether it should be "(void) last_operation(); return 0;".

-std=c90 is not a good option for requesting "I want the random contents of the return register left behind by the last function called in main to be the return value of main, if possible".

Post reply on HN