C character arithmetic turns simple equations into unexpected ASCII chaos
Description
Dark-themed IDE screenshot of main.c. Lines 1-2 show “#include <stdio.h>”. Inside main(), a single printf contains 11 %i specifiers, two %c, and a %s, followed by a list of comma-separated expressions that treat character literals as integers: '1' + '5' + '9', '9' - '2', '9' - 2, '5' + 2 , '5' + 2, 5 + 2, 0 * 1, '0' * 1, '0' * 1, 1 * '0', and finally the string "¯\\_(ツ)_/¯". Each expression has an inline orange comment such as “// 159”, “// still 7”, “// 55 (╯°□°)╯︵┻━┻”, and “// gimme my zero back!”. The black console at the bottom prints: “159 7 7 55 55 7 1 0 0 2401 2352 ¯\_(ツ)_/¯” followed by green text “...Program finished with exit code 0” and “Press ENTER to exit console.” The gag highlights how C promotes character constants to their ASCII codes, making ordinary math yield counter-intuitive results and illustrating language quirks that trip up even experienced developers
Comments
42Comment deleted
C char arithmetic: that blissful reminder your cloud-native service is ultimately negotiating with a 1970s teletype - `'9'-'2'` politely returns 7, then `'1'*'0'` drops 2352 just to prove ASCII still outranks your architecture diagrams
After 20 years of C programming, you realize the real undefined behavior was the friends we segfaulted along the way - and printf format strings are just the compiler's way of testing if you've truly accepted that char arithmetic is both deterministic and chaotic simultaneously
Ah yes, the classic C initiation ritual: discovering that '1' * '1' equals 2401 because you're actually computing 49 * 49 (ASCII values). It's the language's way of teaching you that characters are just integers in a trench coat, and printf will happily let you shoot yourself in the foot while the compiler watches with mild amusement. The progression from confident arithmetic to existential crisis (complete with table flip and look of disapproval) perfectly captures that moment when you realize C's type system is more 'suggestion' than 'safety net.' At least the shrug emoticon printed correctly - small victories in systems programming
C is that place where chars are just ints in cosplay - subtract 2 from '9', printf dresses it back up as '7', and someone files a bug against math instead of the type system
9-2=55? Classic char promotion: comments spill the ASCII tea while printf ghosts the args
C: where '9' - '2' gives 7, but '1' * '0' gives 2352 - ASCII is math and printf will faithfully publish whatever lie you tell about types
uh yeah, that's how chars work Comment deleted
well, this isn't JS Comment deleted
Even in JS you go straight to jail for this Comment deleted
well yes who tf even does this Comment deleted
Perhaps JS guys like "jail things", but in C it is totally legitimate use of char and printf format specifiers (with the exception of character multiplication, which is really weird). Comment deleted
So good hahhaha Comment deleted
Щ Comment deleted
That’s basically ascii codes: '1' = 49, '1' * '1' = 49 * 49 = 2401, '1' + '5' + '9' = 49 + 53 + 57 = 159. Same thing printed as int gives the ASCII code, printed as char gives a symbol for this code Comment deleted
oh, I thought they were manipulating string pointers, but you're right. Comment deleted
'1' * '0' = 49 * 48 = 2352, i guess it’s an ascii code for a symbol similar to zero Comment deleted
does utf-16 count? Comment deleted
except for ascii being valid for charcodes less than 128 - the symbol is probably from unicode Comment deleted
2352 % 256 = 48 = '0' Comment deleted
Yepp! In 2352 in the first byte bits (and char is a byte type) there’s 48 (the rest is in the second byte of the number (short type would be)), so this is the value that is taken and its char '0' is printed Comment deleted
void *ptr = &main; printf("%s", ptr); wow, such C much bad 🤦♂️ Comment deleted
i'm in programming for not long but nr/str type coercion memes... is it that funny? Comment deleted
Come on, it is basic CS Comment deleted
Wait, do the answers line up right to the examples there? I'm confused why '9'- 2 is 7 the first time, and 55 the second time? Wouldn't both be 55? Comment deleted
Based on how I learned from these comments, "9" is 57 in ASCII, and subtracting 2 from it will be 55, which is actually "7" in ASCII but the code returns the value not the character (Correct me if I'm wrong I wanna learn) Comment deleted
it returns the value regardless, but the format string interprets the value as an integer and not as a character. %i → format integer (57) %c → format character ('9') Comment deleted
Thanks!! So I guess %s means string I have no experience in coding, lol Comment deleted
I guess so. I don't have much experience with C, but format strings in python are similar. (at least the deprecated % format strings) Comment deleted
The C standard isn't as easily linkable, so here's the UNIX one which is a superset. Specific implementations (like glibc) may add yet more stuff. https://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html Comment deleted
That's a lot Comment deleted
Standard specifications do be like that. Comment deleted
And yes, while C has no string type the "array of char ending with null" is the most typical way to encode them (AKA C-style strings) and the library functions use "s" as mnemonic for them. For example "sprintf" function above is a variant of "printf" that writes output to char array as opposed to standard output. Comment deleted
Ahh! Man... That feels, crappy :\ Comment deleted
It's error prone. Still, it seems to endure as one of the languages of choice when you need to interface with arbitrary memory layouts outside your control. Not being tied to one single string implementation seems to be an advantage when programming microcontrollers, device drivers, kernel interfaces… or pretty much anything that binds to complex C libraries, though wrapping is to some extent generally possible. If you want even more text there's this long essay about it: http://www.cl.cam.ac.uk/~srk31/research/papers/kell17some-preprint.pdf Some Were Meant for C: The Endurance of an Unmanageable Language by Stephen Kell, University of Cambridge Comment deleted
Thank you Fiona :3 Comment deleted
Look at the %i and %c Comment deleted
Yup, that was my next message. Sod's law, that I spend ages looking over it, and within a minute of asking, I realise the difference Comment deleted
Oh, printing %i vs %c, missed that Comment deleted
coercion joke never die Comment deleted
50 ** "2" == 2500 Comment deleted
Yeah, it's manual memory management + manual error handling. Both of those are things that come up for almost any string operation. That's why AWK exists, for when you need text processing task written fast without caring how it's laid out in memory or how each potential error case needs to be handled. Also lex and yacc. Comment deleted
https://nethackwiki.com/wiki/Source:NetHack_3.6.1/src/hacklib.c#strkitten Comment deleted