Live data from Hacker News

There is no 'printf'

netmeister.org

151–158 of 158 posts

Re: There is no 'printf'

#151
post #140

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…

The "no_std" idea is one that has washed up over and over again, over the last half-century. ISO Standards typically call it "freestanding". It has invariably failed to yield the promised benefits. It hangs around, anyway, cluttering up Standards. People waste endless hours proposing alterations to it for the next Standard edition, to be likewise ignored by implementers and informed users of whichever language. I don…

no_std is already in ubiquitous use in the embedded rust community and does exactly what it says on the tin. Having a no_std feature is extremely common to allow (restricted) crate use in that context.

Re: There is no 'printf'

#152

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

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.

> implicit memsets and memcpys, in cases where it can't be handled within less instructions

Yeah, I know. Still, I expected GCC to generate code like this in freestanding environments. There is no standard library so the compiler should not implicitly emit any calls to standard library functions at all. That ought to have freed me to do whatever I want, including implementing those functions differently or with different names.

> These functions are required by the freestanding part of the C standard, too, anyway.

What? If I remember correctly, only a very small list of headers are required in freestanding environments and string.h was not among them.

Re: There is no 'printf'

#153

Earlier quoted context omitted.

So the compiler actually can't optimize because of legacy errno cruft? That's hilarious...

The compiler respects the C standard by default. According to it, puts() is the same as a printf() in some conditions, but sqrt() is not the same as the instruction. If you don't like C, you can use a dialect of it by setting some flags: -fno-math-errno if you want to optimize sqrt anyway or -fno-builtin if you don't want the compiler to replace functions calls

I like C for the most part. I don't like the standard library. It's got stuff like errno, a thread local global variable, and that's just the simplest problem. Freestanding C turned out to be a far better language just because it has no legacy cruft weighing it down.

> -fno-math-errno

That's interesting, didn't know about it.

Re: There is no 'printf'

#154

Earlier quoted context omitted.

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

It sounds like what you really want is a high-level portable assembler. Which, to be fair, is one of the niches that C has occupied... but I'm not convinced it's optimally designed for that in general, even leaving UB aside. But back in DOS days, there was something called Sphinx C--: https://bkhome.org/archive/goosee/cmm/c--doc.htm . A modern cross-arch reincarnation of that could be interesting.

> high-level portable assembler

Yeah.

More precisely, what I want is something that:

1. Gives me simple native code ELFs

2. Containing no symbols other than the functions I defined

3. That can interface directly with the Linux kernel with zero dependencies

If I bend C enough it turns into something resembling that. Freestanding C, a couple flags to fix the language and the compiler's inline assembly to fulfill the 3rd requirement. I agree that it's not perfect for the role but C compilers are way too important for me to simply disregard them and look for or invent a new language. I'd be giving up too much.

I wish the newer C standards took the time to define previously undefined behavior instead of adding even more cruft to the standard library. C11 is just the opposite of what I wanted.

Re: There is no 'printf'

#155
post #143

Earlier quoted context omitted.

They're all system calls that are better served by using operating functions directly. I'm not sure how the compiler could possibly optimize those away though. Maybe the random function could become a very untrustworthy instruction?

Random number generation generally isn't handled by system calls. It's just computation. (Some languages do provide support for hardware [pseudo-]random number generation. C doesn't.) More generally, using system calls directly for things like getting the current time makes sense only if you don't care about portability. C can support both portable and non-portable code. Both are important. I get the impression that…

> I get the impression that C is too high-level, and assembly language is too tedious, to fully support your requirements.

Definitely seems that way to me as well. Still, if I bend C enough it turns into something that's almost what I want. I just wish GCC had a couple more flags to control code generation in these surprising cases.

Re: There is no 'printf'

#156

Earlier quoted context omitted.

It sounds like what you really want is a high-level portable assembler. Which, to be fair, is one of the niches that C has occupied... but I'm not convinced it's optimally designed for that in general, even leaving UB aside. But back in DOS days, there was something called Sphinx C--: https://bkhome.org/archive/goosee/cmm/c--doc.htm . A modern cross-arch reincarnation of that could be interesting.

> high-level portable assembler Yeah. More precisely, what I want is something that: 1. Gives me simple native code ELFs 2. Containing no symbols other than the functions I defined 3. That can interface directly with the Linux kernel with zero dependencies If I bend C enough it turns into something resembling that. Freestanding C, a couple flags to fix the language and the compiler's inline assembly to fulfill the 3r…

Reducing UB also reduces optimization opportunities, and these days, outside of embedded, C (or C++) is usually used because it's fast - there are better options if that's not a concern. So I don't think that the base C standard will ever do that. But there can be standards derived from it, which provide more rigorous guarantees at the cost of perf.

Then you have embedded, where the norm is either gcc (which loves to optimize away UB), or bespoke compilers produced by the hardware manufacturer that are usually full of weird bugs in any case.

Given that, is C really that important? I can see the ability to parse C headers as somewhat useful for the sake of interop, just so you could use all the libraries (and not just syscalls); but aside from that?

Re: There is no 'printf'

#157
post #122

Earlier quoted context omitted.

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?

If you wrote the same thing in assembly language and, by convention, you return the value from a subroutine in the AX register. This function is not returning anything useful so you don't 'MOV AX,blah', yet your caller expected something in it, is it undefined?

Does the AX register exist in the caller? Yes.

Does it have a value? Yes.

Is its 'value' undefined. Yes.

Is there any undefined 'behaviour' of anything you told it to do? Not to me. Subtle maybe.

Re: There is no 'printf'

#158
post #157

Earlier quoted context omitted.

Is it undefined behavior?

If you wrote the same thing in assembly language and, by convention, you return the value from a subroutine in the AX register. This function is not returning anything useful so you don't 'MOV AX,blah', yet your caller expected something in it, is it undefined? Does the AX register exist in the caller? Yes. Does it have a value? Yes. Is its 'value' undefined. Yes. Is there any undefined 'behaviour' of anything you to…

I mean what the C standard says about it.
Post reply on HN