4 ms·
How did printf end up here in the first place? Decades of feature additions, or were these features a part of an early spec?
by lxe 6y ago
How did printf end up here in the first place? Decades of feature additions, or were these features a part of an early spec?
- segfaultbuserr 6y agoFun fact, on glibc, an extension feature is that you can define your own custom conversion specifiers for printf().
- wahern 6y ago%n was defined in C89, the first C standard: http://port70.net/~nsz/c/c89/c89-draft.html#4.9.6.1 http://port70.net/~nsz/c/c89/c89-draft.html#4.9.6.1 Looking at old source code, the earliest implementation I found is 4.3BSD Tahoe (1988). See https://www.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Tahoe/usr/src/lib/libc/stdio/doprnt.c https://www.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Tahoe/usr/... Second oldest I found was Tenth Edition [Research] Unix (1989). See ocvt_n at https://www.tuhs.org/cgi-bin/utree.pl?file=V10/libc/stdio/vfprintf.c https://www.tuhs.org/cgi-bin/utree.pl?file=V10/libc/stdio/vf... I couldn't find support in earlier implementations archived on that site.
- segfaultbuserr 6y ago> Looking at old source code, the earliest implementation I found is 4.3BSD Tahoe (1988). You are the HN historian of the day.
- wahern 6y agoAnother interesting factoid is that macOS only supports %n if the format string is located in read-only memory. Per printf(3) on macOS: > For this reason, a format argument containing %n is assumed to be untrustworthy if located in writable memory (i.e. memory with protection PROT_WRITE; see mprotect(2)) and any attempt to use such an argument is fatal. Practically, this means that %n is permitted in literal format strings but disallowed in format strings located in normal stack- or heap-allocated memory. The manual page seems correct: % cat test.c #include <stdio.h> int main(void) { printf((char[]){ "%n" }, &(int){ 0 }); return 0; } % cc -o test test.c % ./test zsh: abort ./test
- saagarjha 6y agoSomeone should inform The Open Group about this violation of POSIX ;) Another fun fact: glibc does this too, if you compile with -D_FORTIFY_SOURCE=2. However, since Linux lacks the nice vm_region APIs the code opens up /proc/self/maps :/
- astrange 6y agodyld on Darwin has an API to ask if any pointer is to a read-only section of a binary. It’s useful because you can e.g. skip strcpys and other allocations.
- saagarjha 6y agoHmm, can you tell me more? I can't think of any situation where skipping on a strcpy is legal, since you provide the second buffer and so the copy must occur. And I know that there is heavy uniquing going on for things like selectors and CFStrings at compile time, but where is the dyld API being used at runtime?
- astrange 6y agoOh, I meant strdup. Look for stdupIfMutable() calls in libobjc.
- pjmlp 6y agoThat is the beauty of POSIX, write once, debug everywhere, fix with plenty of spaghetti #ifdefs.
- Narishma 6y agoI'm pretty sure the compilers from Microsoft and Borland supported %n earlier than that. The earliest one I have easy access to that supports it is Microsoft C 4.0 from 1986.
- gambiting 6y agoDoes anyone know why it was introduced in the first place? I mean.....the return value of printf gives you the exact same information, no? Why give printf the ability to write anything in the first place?
- gambiting 6y agoAh, I found out why - %n prints out the number of characters printed up to the point where the %n is. Printf returns the total number of characters printed.