Skip to content
DevMeme
4518 of 7590
Languages Post #4958 · source on Telegram

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

42
Anonymous ★ Top Pick 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
  1. Anonymous ★ Top Pick

    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

  2. Anonymous

    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

  3. Anonymous

    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

  4. Anonymous

    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

  5. Anonymous

    9-2=55? Classic char promotion: comments spill the ASCII tea while printf ghosts the args

  6. Anonymous

    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

  7. @Similacrest 3y

    uh yeah, that's how chars work

  8. 𝙳𝚖𝚢𝚝𝚛𝚘 𝙼𝚒𝚗𝚝𝚎𝚗𝚔𝚘 3y

    well, this isn't JS

  9. @Alex_Helion 3y

    Even in JS you go straight to jail for this

    1. 𝙳𝚖𝚢𝚝𝚛𝚘 𝙼𝚒𝚗𝚝𝚎𝚗𝚔𝚘 3y

      well yes who tf even does this

    2. @SamsonovAnton 3y

      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).

  10. @ZgGPuo8dZef58K6hxxGVj3Z2 3y

    So good hahhaha

  11. @s_yak_dollar 3y

    Щ

  12. @anatoli26 3y

    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

    1. @RiedleroD 3y

      oh, I thought they were manipulating string pointers, but you're right.

  13. @anatoli26 3y

    '1' * '0' = 49 * 48 = 2352, i guess it’s an ascii code for a symbol similar to zero

    1. 𝙳𝚖𝚢𝚝𝚛𝚘 𝙼𝚒𝚗𝚝𝚎𝚗𝚔𝚘 3y

      does utf-16 count?

    2. @sylfn 3y

      except for ascii being valid for charcodes less than 128 - the symbol is probably from unicode

    3. @CcxCZ 3y

      2352 % 256 = 48 = '0'

      1. @anatoli26 3y

        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

  14. @poniraq 3y

    void *ptr = &main; printf("%s", ptr); wow, such C much bad 🤦‍♂️

  15. @Horace4815162342 3y

    i'm in programming for not long but nr/str type coercion memes... is it that funny?

  16. Денис 3y

    Come on, it is basic CS

  17. @deerspangle 3y

    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?

    1. @Vanilla_Danette 3y

      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)

      1. @RiedleroD 3y

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

        1. @Vanilla_Danette 3y

          Thanks!! So I guess %s means string I have no experience in coding, lol

          1. @RiedleroD 3y

            I guess so. I don't have much experience with C, but format strings in python are similar. (at least the deprecated % format strings)

          2. @CcxCZ 3y

            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

            1. @Vanilla_Danette 3y

              That's a lot

              1. @CcxCZ 3y

                Standard specifications do be like that.

          3. @CcxCZ 3y

            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.

            1. @Vanilla_Danette 3y

              Ahh! Man... That feels, crappy :\

              1. @CcxCZ 3y

                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

                1. @Vanilla_Danette 3y

                  Thank you Fiona :3

    2. @FunnyGuyU 3y

      Look at the %i and %c

      1. @deerspangle 3y

        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

  18. @deerspangle 3y

    Oh, printing %i vs %c, missed that

  19. @dsmagikswsa 3y

    coercion joke never die

  20. @glatavento 3y

    50 ** "2" == 2500

  21. @CcxCZ 3y

    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.

  22. @CcxCZ 3y

    https://nethackwiki.com/wiki/Source:NetHack_3.6.1/src/hacklib.c#strkitten

Use J and K for navigation