Where the Printf Rubber Meets the Road (2010)
blog.hostilefork.com
blog.hostilefork.com
Let the record show, also, that I in no way stand by this as being a sane approach. I just walked through it, trying to answer the question. I wanted to show the path to syscall and it was way wackier than I thought it would be. That's why it ended up a blog entry.
(Though when my blog went down one day, someone copied the content into the answer:
http://stackoverflow.com/revisions/2444508/3
...and they did so ignoring the license clause difference that my blog is CC-BY-NC-SA instead of CC-BY-SA. There's been a bit of a tussle over that distinction lately, with people selling StackOverflow books:
http://meta.stackoverflow.com/questions/272768/is-this-site-...
...and I'll leave it to those with more interest in the issue to decide if that is worth worrying about, because I don't actually care.)
Anyway, I'm sure the people involved in writing this had their reasons for doing it this way, and it had to do with code legacy and evolution. I don't want anyone to mistake my trace through it as endorsement. It's just what it is.
Search for register_printf_function, and realize that printf is now a function that can have whatever side-effects you like (which really sucks for optimization around logging code)
__attribute__ ((format (printf, 1, 2)))
attaches to a function declaration to indicate that the function works like printf, so GCC can warn if a (compile time) format string does not match the variadic arguments. But there seems to be no way to extend this attribute, nor to make entirely new attributes in the same spirit.So you can register new format specifiers for printf, but it seems you'll then have to disable warnings about bad format specifiers during compilation. Those warnings have very few false positives and catch real bugs in real code.
Yes, GCC knows, and we're good with that :)
The glibc extension here serves no earthly purpose (and on the gcc side, we've considered pretending it doesn't exist before so we can actually optimize better).
It sounds like it may be a good idea, except 1. It modifies functions that have a standard purpose, standard set of format specifiers, and are, as you point out, often error checked to make sure they match those :)
2. Unless you see the printf handler registration, which may be in a library, linked to your program, or whatever, you'll have no idea that the code is wrong.
You might think, but who in their right mind would redefine printf()? But C has an infinite number of people using it all the time, so every possible weird thing has been done a few times by now.
Note that GCC assumes it isn't redefined unless you use -fno-builtin-printf.
It will replace printf calls with puts and do other fun things.
One cannot discount those in their wrong mind either.
I had a header dedicated to #undef ing things ruby.h redirected so I could include it in C++ contexts without breaking the SC++L. While I don't see printf on the list, read, write, close, fclose, sleep, and many more are.
In the end, I did find out a way to write to stdout without calling putchar or including stdio directly, but there's still some mystery in the call to write:
// Printing to stdout without stdio or putchar
// Originally adapted from here:
// http://stackoverflow.com/a/14296280
void print_char(char item, int len)
{
for (;len; --len)
{
write(1, &item, 1);
}
}
[0] - https://github.com/lelandbatey/tiny_tree_printer[0] - http://lelandbatey.com/posts/2014/09/binary-tree-printer/
The OpenBSD C library is the one I usually look at when I want to understand how a specific function works. It doesn't have insane optimizations or bloat like glibc, but it's clean and portable.
Regarding the site hosting the article: ugh, it's bad enough to capture the left arrow key and have it go to a previous article, but pay attention to the modifiers to avoid breaking alt-left as a keyboard shortcut for "back". (Browsers shouldn't even allow unprivileged pages to override shortcuts like alt-left.)
It irritates me that a low-tech site run by loudmouth self-important non-philosopher startup "We're Big Business" people is worshipped so mindlessly by the madding JavaScript crowds. I guess they don't know any better. They're kids.
And the logo... it's a Y. Must have taken a long time to make that! Can I trade my "points" here for anything besides meaningless points on something that is only slightly lower tech than Reddit?
It's not your fault that these people--this rep system--this fraud exists. But sadness for me and my heart, because I care about right answers and beautiful things. "Startups" and "entrepreneurs" who don't have a soul or an original idea in their head aren't part of my world. Show me something amazing, or come to me with a question. Not the junk from these clowns.
So I'm back to answering homework questions for poor kids in India who don't know that Turbo C is long discontinued. I want to improve the world.
I wish computers hadn't gotten cool enough to get on the radar of MBA wannabe mental lightweights.
http://api.ning.com/files/7p9j8xEwRdVx32byvos40sX-7FeEGhQJ6Z...
Business, business business. Numbers. Is this working?
Get some, and you can change the color of the header bar. Get about 500 and you can downvote people. That's about it.
Well maybe these modernizations are good. You shoot people in the face virtually.
I'm traveling and it's not convenient to fix it tonight, but I will do it as soon as I can.
I'm sure there is some political reason why ldbl_strong_alias was used to rename printf to __printf, but frankly I don't really care, there are macros like that all over the C/C++ libraries that make finding the source for anything pure hell.
The only acceptable macro to me now is a block which only runs in the DEBUG build and is skipped over by the compiler in RELEASE.
PS - Yes this is why I don't code in C/C++ very often. I'm currently playing with Go which has no concept of macros.
another huge benefit is that they take care of fiddly bookkeeping for you - if you have to remember some incantation that involves doing several steps in sequence and making sure that if you change place A you need to change B and C in certain ways, just write a macro and be happy.
Printing floating-point numbers is also another topic that is subtly more difficult than it looks at first glance... here's one of the better articles about it: http://www.ampl.com/REFS/rounding.pdf
And for that type of C newbie who hasn't seen varargs... I'd say the answer is pretty intuitive if you know how to look. First of all the answer is staring at you in the manpage:
int printf(const char *s, ...);
int vprintf(const char *s, va_list ap);
OK, so there is the set of ordinary C functions that do it. Look up this va_list thing and an implementation becomes obvious... printf sets up a va_list and calls vprintf... vprintf scans the string for '%' and uses va_arg...But the important thing is none of this is magic and you can totally guess it just by looking at documentation. I don't think it ever confused me when I learned C. I don't really get why this is so shocking to people who read the manpages.
> Visual Studio x64 doesn't support inline assembler. That doesn't mean you can't have assembler code. You can still have assembler, just not inline.
and in the answer section
> The system calls are (on platforms that I know of) internally implemented by a call to a function with inline asm that puts a system call number and parameters in CPU registers and triggers an interrupt that the kernel then processes.
Since Visual Studio is mentioned, I'll say that despite some extra layers (CRT, kernel32, ntdll) the concepts are identical and when I was a kid learning C I was able to dig through header files and documentation to conceptually figure it out.
I still say, they don't understand varargs, don't understand the difference between stdio and write(), and most importantly, they are not curious enough to read documentation and make smart guesses. And I am saying, the bullshit obfuscation involved in this article, sharing so many meaningless implementation details about a very specific libc, will not help answer this question or gain insight more than RTFMing and being curious about the world would.
So... If you are even asking questions like... "Does printf use assembly?" I'd argue you are not thinking it through. You need to get yourself to a place where you can answer that yourself. It will be a very obvious answer when you do. Writing frivolous blog posts is not the way to get there.
http://www.red-lang.org/p/contributions.html
We're trying to undo this stuff. I was just answering a question.
It's moving slower than we'd like, but definitely moving.