Live data from Hacker News

There is no 'printf'

netmeister.org

91–100 of 158 posts

Re: There is no 'printf'

#91

Compiler optimization is really annoying sometimes. It's allowed to assume that functions with the same name as standard library functions behave according to standard. They'll swap out printf calls for puts if they don't have a format. The compiler just knows it can do that. Sure, it optimizes things but it gets to the point the code no longer reflects what's written on the source file. Try to hook into printf and i…

Do you also expect `sqrt(a)` to be `call sqrt` and not `sqrtss xmm0`?

> Do you also expect `sqrt(a)` to be `call sqrt` and not `sqrtss xmm0`?

Of course. Who else is going to set errno when I pass negative a number?

Re: There is no 'printf'

#92

Earlier quoted context omitted.

Because it doesn't really matter how the program calculates mathematical functions as long as the result is correct. Whether it's a function or an instruction, it's inconsequential. I/O on the other hand is a lot more interesting. They're a very common source of undefined behavior, bugs and interception via custom shared objects. I'd rather the compiler touched them as little as possible. Actually I'd rather not use…

What about datetime, random, system, etc?

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?

Re: There is no 'printf'

#93

Earlier quoted context omitted.

Do you also expect `sqrt(a)` to be `call sqrt` and not `sqrtss xmm0`?

> Do you also expect `sqrt(a)` to be `call sqrt` and not `sqrtss xmm0`? Of course. Who else is going to set errno when I pass negative a number?

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

Re: There is no 'printf'

#94
post #66

Earlier quoted context omitted.

OK, but this doesn’t do wonders as a counterargument that C is just a big pile of historical baggage.

Like the article says, this got cleaned up over 20 years ago in C99. But sure, I wouldn't recommend anyone choose C as a language for new software unless they have an extremely good reason, or if you really love stuff like implementing every data structure you use from scratch and using void* as a kind of wildly unsafe generic.

> I wouldn't recommend anyone choose C as a language for new software

Unless you are doing firmware where all those constraints are still around, and you have to deal with whatever compiler the vendor supplies for their microcontroller, which will almost certainly be some variant of C.

Re: There is no 'printf'

#95

> But what if you're not using C99 or newer? If you're using C90, but under an implementation that supports C99, that implementation should obey all the new rules in all areas where there is no conflict between C90 and C99. The ISO C90 standard is obsolescent, so the fact that dropping off the end of main with no return value is an unspecified termination status is an obsolescent requirement (or non-requirement). It…

> There is no good reason for a C99 implementation behaving in a C90 compatibility mode to simply drop non-conflicting C99 requirements and revert a behavior such as this. A compatibility with a code which depends on a behaviour of a previous version of the compiler is a reason enough. If compatibility is dropped you now have a very subtle bug which is hard to discover and understand unless you read about that partic…

There's no compatibility requirement here, because the old behavior is UB (both in theory and in practice).

Re: There is no 'printf'

#96
post #72

Earlier quoted context omitted.

The first function (the `n == 0 || !isEven(n+1)` recursive function) has defined behavior for negative numbers. That's probably why it compiled to an even number check.

Hmm you're right that there's definitely more to the first function than coincidence. I dug a bit deeper and surprisingly when n is unsigned the function is still well defined and correct. [0] AFAIK clang will usually just treat a signed overflow as an unsigned overflow when optimizing as it simplifies things. So my bet would be that clang is just casting n to unsigned and performing some inductive reasoning similar…

> 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 reasoning to work through there.

Thanks for taking the time to explain!

Re: There is no 'printf'

#98
post #94
post #66

Earlier quoted context omitted.

Like the article says, this got cleaned up over 20 years ago in C99. But sure, I wouldn't recommend anyone choose C as a language for new software unless they have an extremely good reason, or if you really love stuff like implementing every data structure you use from scratch and using void* as a kind of wildly unsafe generic.

> I wouldn't recommend anyone choose C as a language for new software Unless you are doing firmware where all those constraints are still around, and you have to deal with whatever compiler the vendor supplies for their microcontroller, which will almost certainly be some variant of C.

Thankfully there are vendors that still bother to sell Basic, Pascal compilers for tiny microcontrollers.

But yeah doing so is being a special snowflake, still they are in business to this day.

Re: There is no 'printf'

#100
post #72

Earlier quoted context omitted.

The first function (the `n == 0 || !isEven(n+1)` recursive function) has defined behavior for negative numbers. That's probably why it compiled to an even number check.

Hmm you're right that there's definitely more to the first function than coincidence. I dug a bit deeper and surprisingly when n is unsigned the function is still well defined and correct. [0] AFAIK clang will usually just treat a signed overflow as an unsigned overflow when optimizing as it simplifies things. So my bet would be that clang is just casting n to unsigned and performing some inductive reasoning similar…

max(unsigned int) being odd is also required by the C standard; C17 6.2.6.2/1:

"For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2*(N-1), so that objects of that type shall be capable of representing values from 0 to 2*(N-1) using a pure binary representation; this shall be known as the value representation."

Post reply on HN