Skip to content
DevMeme
4518 of 7435
C character arithmetic turns simple equations into unexpected ASCII chaos
Languages Post #4958, on Oct 28, 2022 in TG

C character arithmetic turns simple equations into unexpected ASCII chaos

Why is this Languages meme funny?

Level 1: Numbers in Disguise

Imagine you have a secret decoder ring where every letter or symbol is really just a number. For example, say the code for 'A' is 1, 'B' is 2, and so on (in real life ASCII, the code for 'A' is 65, but let’s keep it simple). Now, if I asked you to add '1' and '5' – not the numbers one and five, but the character '1' and the character '5' from your keyboard – the computer doesn’t see them as the symbols you see. It sees their secret numbers! Let’s pretend '1' has a secret number 49 and '5' has 53 (that’s actually true in ASCII). The computer adds 49 + 53 and gets 102. It doesn’t magically understand that you maybe wanted the number 6; it just adds the secret codes. If you tell the computer “print this as a number,” it will print 102. If you tell it “print this as a letter,” it will look at 102 and go “hmm, 102 in my code chart is the letter 'f'” and print that. That’s pretty confusing, right?

The meme is a joke about this exact confusion. The programmer did math with characters like '9' and '2' and got some funny results. At one point they subtract the secret codes for '9' and '2'. Coincidentally, that gives 7, which looks normal (9 - 2 is 7, after all!). But then they tried a slightly different way and got 55, which is weird. They even did multiplication with '1' and '0', expecting 1×0 = 0, but because those were secret code numbers (49 and 48), they got a huge number instead. In the end, the programmer prints a shrug emoji like “I have no idea what’s going on ¯_(ツ)_/¯.” The feeling is like if you tried to do simple math homework but every time you wrote a number, it turned out you were actually using some secret code and the answers came out bizarre. It’s funny because we expect computers to do what we mean, but here the computer is doing exactly what we said (adding secret code numbers) and the result looks like nonsense to us. So the joke is: in the C programming language, letters and symbols are really just numbers in disguise, and if you treat them like regular numbers, you might get some very surprising answers!

Level 2: When '1' Isn’t 1

Let’s break down what’s happening in this meme step by step. First, remember that in C (and other C family languages like C++), a char is a data type that typically holds an ASCII character. But under the hood, that character is stored as a number (the ASCII code). ASCII is a standard mapping of characters to integer values. For example, the character '0' has ASCII value 48, '1' has value 49, '5' is 53, and '9' is 57. These are just fixed codes the computer uses to represent those characters in memory. So if you see something in C like '1', that means the character '1', which is numerically 49, not the number one. This is a common point of confusion for beginners.

Now, C is designed such that if you use character values in arithmetic expressions, it treats them as integers (this is called integer promotion). That means you can do math with them, but you’ll be doing math on their ASCII codes. The meme’s code uses printf with a bunch of format specifiers to output results of these char-based calculations. The format specifiers %i or %d mean “print this argument as a signed integer (in decimal)”, %c means “print this argument as a character”, and %s means “print this argument as a string”. The code passes a series of weird expressions as arguments, like '1' + '5' + '9', '9' - '2', '9' - 2, '5' + 2, etc., and each has an inline comment predicting the result. Let’s decode a few:

  • '1' + '5' + '9': Each of those is a char literal. So it’s really 49 + 53 + 57. Add those up, you get 159. That’s why the comment says // 159 and the program’s output starts with 159. No characters are being concatenated here – it’s pure addition of code numbers.
  • '9' - '2': Char '9' is 57, char '2' is 50. Subtracting gives 7. If you print 7 as an integer, you see “7”. The code’s comment // 7 and the output showing 7 confirm this. Interesting aside: '9' - '0' would give 9, which is a common trick to convert a digit character to its numeric value. Here they used '2' just to show it still works out neatly to 7 because 57-50 = 7.
  • '9' - 2: Here '9' (57) minus the number 2 (not the char '2' this time) yields 55. The code jokingly comments “// still 7” because when they printed it, it looked like 7 again. How? They likely used %c to print that 55, and ASCII code 55 corresponds to the character '7'. So even though the calculation result was 55, printing it as a char made a "7" appear on the screen. This demonstrates how using %c versus %i can show you two different interpretations of the same number.
  • '5' + 2: Char '5' is 53. Add 2 gives 55. If you print that as a number, you get “55”. The comments “Lol jk it’s 55” and the table-flip emoticon in the code reflect someone expecting maybe a 7, then realizing it’s 55 and expressing playful frustration. The program indeed prints 55 at that spot. Immediately after, the code does 5 + 2 (now 5 is an actual int literal five). 5 + 2 = 7, no surprises. The comment “actually no, it’s 7” is clarifying that when you’re dealing with real numeric values (not char codes), 5+2 behaves normally.
  • 1 * 1: This is straightforward, just 1 (int) times 1 equals 1. Comment says “one” and output shows 1.
  • '0' * 1: Char '0' is 48. Times 1 is still 48. Now, if the program printed 48 as an integer, we’d see “48” in the output. But the output shows 0 instead, which implies they likely printed it with %c. 48 as an ASCII code is the character '0'. So printing 48 as a char displays 0. The comment “// zero” is hinting that the result looks like zero. They do '0' * 1 again (probably just to double-check, humorously), and comment “// still zero” – and indeed the next output is another 0. So they cleverly made 48 appear as “0” by treating it as a character.
  • 1 * '0': Now this one is wild at first glance. If it were 1 * 0 (one times zero) it’d be 0, but here it’s 1 * '0'. That means 1 * 48 (since '0' is 48). That equals 48. If printed as an integer, it would be 48. But oddly, the output shows 2401 at that position, which suggests maybe the code line in the meme was slightly different or they did something extra (perhaps '1' * '1' somewhere, because 4949 = 2401). Let’s assume they meant '1' * '1' gave 2401 (4949) and then '1' * '0' gave 2352 (49*48) as the final number – because the output has 2401 then 2352. In any case, the key takeaway is: '1' * '0' means you're multiplying the ASCII codes of '1' and '0', i.e. 49 * 48, which equals 2352. Printing that as a normal integer just dumps “2352” to the console. The comment “gimme my zero back!” is a joke on how 1×0 in normal math is 0, but here we lost that intuition completely; we got a huge number instead, because we multiplied character codes.

Finally, the printf ends with a %s and the string literal "¯\\_(ツ)_/¯". That’s how they got the shrug emoticon to print out at the end (the backslashes are just escaping characters so that the console shows ¯\_(ツ)_/¯). It’s basically the coder shrugging at the results, saying “Oh well, C is weird, what can you do? ¯_(ツ)_/¯”

So, in summary: this meme is demonstrating that in C, characters are represented by their ASCII numeric values. Doing arithmetic on them manipulates those numeric codes, not the human-friendly digit they might represent. And depending on how you print the result (as a number or as a character), you’ll either see the raw number or a possibly nonsensical character. It’s a playful way to show a fundamental C concept: letters and symbols are stored as numbers, so be careful when you mix them with arithmetic! Even if you’re new to C, the lesson here is clear: '1' is not the same as 1 – one is a character code, the other is an integer value. The computer will happily crunch the codes, even if you meant something else. Always pay attention to those quotes and data types. And if something prints as “weird gibberish” or an unexpected number, double-check if you accidentally treated a char as a number or vice versa. This little program intentionally creates that confusion to make us laugh and learn.

Level 3: ASCII Chaos Unleashed

For experienced developers, this meme hits on that “oh C, you rascal” moment. It’s showcasing a classic language quirk: in C, doing arithmetic with character literals can lead to results that look utterly bizarre unless you remember the ASCII values involved. The humor comes from how simple equations suddenly turn into an ASCII circus. The code is intentionally adding and multiplying character constants, then printing them with various %i (integer) and %c (char) format specifiers to produce a string of unexpected outputs. The console at the bottom lists results like 159 7 7 55 55 7 1 0 0 2401 2352 followed by the shrug emoji ¯\_(ツ)_/¯. At first glance, it’s pure nonsense: where on earth do 159 or 2401 come from when you’re seemingly adding or multiplying single-digit numbers? Seasoned C devs quickly realize what’s up: those single quotes in the code mean those aren’t the numbers 1, 5, 9 – they’re character constants. The sum '1'+'5'+'9' is adding the ASCII codes of those characters (49 + 53 + 57), yielding 159. The code comment // 159 next to it confirms that was deliberate. Then it gets cheeky: '9'-'2' is subtracting the code of '2' (50) from the code of '9' (57), resulting in 7 – which, amusingly, is the actual difference of the digits 9 and 2 as well. The comment “// 7” shows it worked out nicely. But then '9' - 2 (note the second operand is the integer 2, not the char '2') gives 57 - 2 = 55. If you print that 55 as an integer you’d see "55", but if you print it as a character you’ll see the character with ASCII code 55, which is '7'. The meme’s output shows two 7s in a row, implying one was printed as a number 7 and the other as the character '7' – visually identical output, but achieved in two hilariously different ways! The inline comment “// still 7” wryly notes that even after subtracting an int 2 from '9', the printed result ended up looking like 7 (because it literally became the character '7'). This is the kind of quirk that bewilders even pros if they forget the subtle difference between '2' and 2.

The humor escalates with '5' + 2. Intuitively, someone might expect '5' + 2 to somehow yield 7 (thinking of the character '5' as the number 5), but in C that’s not how it works – '5' is 53, plus 2 gives 55. The code’s comments // Lol jk it’s 55 and a table-flip emoticon (╯°□°)╯︵┻━┻) capture that feeling of exasperation when you realize you didn’t get 7; you got 55 instead. And indeed, the output prints 55. Right after, the code shows 5 + 2 (without quotes, actual integers) which does yield 7 normally, with a comment “// actually no, it’s 7” – a playful way of saying “relax, when we use real numbers, 5+2 is still 7.” This contrast highlights how mixing up character codes with numeric values can lead to confusion.

The later expressions get even more bonkers: 1 * 1 is straightforward (it prints 1 – the comment “// one” is just spelling it out), but '0' * 1 is where things get spicy. '0' as a char has ASCII code 48, multiply that by 1 and you still get 48. If interpreted as a character, 48 corresponds to '0'. The meme shows two entries for '0' * 1 in a row, both resulting in 0 in the output. This suggests the code probably printed one of them as an integer (which actually would have shown 48, unless they cast or played another trick) and one as a char, yet they cheekily comment “// zero” and “// heck yeah still zero” (the meme’s description censors some language) to imply that whichever way you print it, you're seeing a zero. In reality, they likely used %c both times for comedic effect, because printing 48 as an integer would show “48”, not “0”. By using %c, they pass 48 and get the character '0' printed. So it looks like zero in the console output, even though under the hood it was 48. That double-confirmation “still zero” joke is something a jaded C dev might do to celebrate that the trick worked – the character '0' printed out as “0”, phew!

Finally, we get to the craziness of multiplication: 1 * '0' and '1' * '0'. Now '1' is 49 and '0' is 48, so '1' * '0' computes 49 * 48 = 2352. And indeed the last number in the output is 2352 with the comment “// gimme my zero back!” – because obviously 1×0 is supposed to be 0 in normal math, and here we got a giant 2352 thanks to treating the characters' codes as operands. The second-to-last result, 2401, hints at perhaps '1' * '1' (49 * 49) snuck in there too – 2401 is 49² – which might have been a slight mix-up in the text vs. code, but the essence is the same: multiplying char codes yields huge numbers that have nothing to do with the numerical concept of the digit characters. The author ends the output with the famous shrug emoji ¯\_(ツ)_/¯ (printed via the %s string specifier) as the final flourish – basically saying “We did all this weird stuff, and hey, it prints exactly this shrug, because who knows why I attempted this?!” It’s the coder’s way of shrugging at the absurdity.

For the seasoned crowd, this is a nod to all those “gotcha” moments in C: forgetting that '0' isn’t 0, or that 'A' + 1 yields 'B' by lucky design of ASCII, or using the wrong format specifier in printf and getting gibberish output. It’s both a joke and a gentle reminder: C will happily do what you ask, not necessarily what you mean. The meme encapsulates the shared experience of debugging code where the math doesn’t make sense until you realize you’ve been doing arithmetic on character codes. It’s equal parts frustrating and funny – a classic inside joke among C and low-level programming aficionados.

Level 4: Promotion Commotion

Under the hood, this meme pokes fun at C's type promotion rules and raw ASCII arithmetic. In C, character literals like '1', '5', and '9' aren't magical “digit” objects – they’re actually integers representing ASCII codes. During arithmetic, C automatically promotes char values to int (this is part of the "usual integer promotions" in the C standard). So '1' becomes the integer 49 (since the ASCII code for the character '1' is 49), '5' becomes 53, and '9' becomes 57 before any addition or subtraction happens. The sum '1' + '5' + '9' therefore turns into 49 + 53 + 57, which equals 159. It’s not doing string concatenation or base-10 math – it’s literally adding three byte values. The ASCII table underlies all of this: the character codes for digit characters '0' through '9' are sequential (48 through 57 in decimal), which is why '9' - '2' works out to 57 - 50 = 7. This happens to equal the numeric difference of 9 and 2, but only because of ASCII’s clever design. The meme’s code exploits these values and C’s permissive type system to create seemingly nonsensical math results (like 2401 and 2352 from multiplying characters) that actually make sense at the machine level.

The printf formatting here adds another layer of technical nuance. In C’s variadic functions (like printf), char arguments get promoted to int when passed, so whether you write printf("%c", someChar) or printf("%i", someChar), the function actually receives an int either way. The difference is in how printf interprets that int for output: %c will print the character corresponding to the code (by effectively taking the int and treating it as an unsigned char internally), whereas %i (or %d) will print the int as a decimal number. So if you hand printf the integer 55 and use %c, it will output the character with code 55 (which is '7'), but using %i would output 55. C doesn’t do any automatic “it looks like a digit so I’ll convert it” magic; it trusts the format specifier. This is why mixing up or intentionally swapping %c and %i can produce chaotic results: the same numeric value can appear either as a number or a gibberish character depending on the specifier. In the meme’s code, the author alternates between %i and %c in the format string, feeding in expressions like '5' + 2 (which yields 55) twice – once printed as an integer (55), and once printed as a character (which appears as '7' on screen, since ASCII 55 is '7'). The comments like “// Lol jk it’s 55” and the tableflip emoticon indicate the moment of shock when a developer realizes that adding 2 to the character '5' doesn’t yield 7 (as a number) but rather the ASCII code 55. There’s no run-time type check to warn you – C expects you to know what you’re doing. This design dates back to C’s low-level roots: treating characters as numbers was efficient and useful (for example, 'A' + 1 giving 'B' if using ASCII). But it also leads to “ASCII chaos” when you naively treat character constants like their human-readable values. Even seasoned C developers can get tripped up by these details, especially when moving between languages – what’s obvious in Python or Java (where '9' might be an error or a very different type) can be a hidden bug in C. The meme ultimately highlights a fundamental truth of C and many C family languages: characters are just tiny numbers in disguise, and if you do math with them, you’d better know the code points! It’s a nerdy celebration of C’s simplicity and its sneaky complexity – a reminder that underneath our source code, everything is just bits and bytes.

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