3
votes

I copied this below code from Stack Overflow's 404 Not Found Error Page.

# define v putchar
# define print(x)
main(){v(4+v(v(52)-4));return 0;}/*
#>+++++++4+[>++++++<-]>
++++.----.++++.*/
print(202*2);exit();
#define/*>.@*/exit()

The above code compiles fine and prints 404 on the console. I thought the statement print(202*2); is responsible for printing 404, but I am not right because changing the numbers in this statement also prints 404.

Could somebody help me to understand this code and how it prints 404?

Am posting the compilation output for your reference as there are comments saying this code doesn't compile. The file containing above code is Test.c.

gcc Test.c -o Test

Test.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int] main(){v(4+v(v(52)-4));return 0;}/* ^ Test.c: In function ‘main’: Test.c:1:12: warning: implicit declaration of function ‘putchar’ [-Wimplicit-function-declaration] # define v putchar ^ Test.c:3:8: note: in expansion of macro ‘v’ main(){v(4+v(v(52)-4));return 0;}/* ^ Test.c: At top level: Test.c:6:14: warning: data definition has no type or storage class print(202*2);exit(); ^ Test.c:6:14: warning: type defaults to ‘int’ in declaration of ‘exit’ [-Wimplicit-int] Test.c:6:14: warning: conflicting types for built-in function ‘exit’

./Test

404

4
putchar(52) outputs 4; 52-4 = 48; putchar(48) outputs 0; 48+4 = 52; putchar(52) outpus 4 again.Jonathan Leffler
Just asking: Dear Migration to MSO voters: can you please add a little justification? I think I'm missing something here on why is should be migrated?Sourav Ghosh
@SouravGhosh; It should be migrated because it has been asked on meta stackoverflow and there are some good answer already there.haccks
@Beginner No, it is impossible to compile this on a standard-compliant C compiler without rewriting most of it.Lundin

4 Answers

1
votes
# define v putchar

this defines v as the putchar() function. It prints a character and returns it.

# define print(x)

this defines print(x) as nothing (so print(202*2) means nothing)

main(){v(4+v(v(52)-4));return 0;}/*

this could be rewritten as:

main()
{
  putchar(4 + putchar(putchar(52) - 4));
  return 0;
}

it is using ASCII codes to print '4' (code 52), '0' (code 52 - 4 = 38) and again '4', so "404".

That line ends with a /* starting a comment the continues through the next two lines:

#>+++++++4+[>++++++<-]>
++++.----.++++.*/

The line below turns out empty, but it is a bit tricky because exit() is defined as empty AFTER the line itself. That works because the C preprocessor runs BEFORE the compilation.

print(202*2);exit();

The line below defines exit() as empty, used on the line above.

#define/*>.@*/exit()
2
votes

Cannot use a meta-question as dupe, so blatantly copying from the MSO answer.

Since this is tagged and mentioned "compiled", so just extracting the C part of it.

Credits: Mark Rushakoff is the original author of the polyglot.

The C code is fairly easy to read, but even easier if you run it through a preprocessor:

main(){putchar(4+putchar(putchar(52)-4));return 0;};exit();

Your standard main function is declared there, and exit is also declared as a function with an implicit return type of int (exit is effectively ignored).

putchar was used because you don't need any #include to use it; you give it an integer argument and it puts the corresponding ASCII character to stdout and returns the same value you gave it. So, we put 52 (which is 4); then we subtract 4 and output 0; then we add 4 to output 4 again.

Also, a little more elboration, from [Cole Johnson's] (https://meta.stackoverflow.com/users/1350209/cole-johnson) answer

Disregarding all of that, when we reformat the code a bit, and replace 52 with its ASCII equivalent ('4'), we get:

int main() {
    putchar(4 + putchar(putchar('4') - 4));
    return 0;
}

As for the putchar declaration, it is defined by the standard to return it's input, like realloc. First, this program prints a 4, then takes the ASCII value (52), subtracts 4 (48), prints that (ASCII 0), adds 4 (52), prints that (4), then finally terminates. This results in the following output:

404

As for this polyglot being valid C++, unfortunately, it is not as C++ requires an explicit return type for functions. This program takes advantage of the fact that C requires functions without an explicit return type to be int.

1
votes

The code cannot compile on a standard C compiler, such as gcc -std=c11 -pedantic-errors.

1) main must return int on hosted systems.
2) putchar() must have #include <stdio.h>.
3) You can't write semicolons outside functions.

After fixing these beginner-level bugs and removing all superfluous fluff that doesn't do anything but creating compiler errors, we are left with this:

#include <stdio.h>
#define v putchar
int main(){v(4+v(v(52)-4));return 0;}

This revolves around putchar returning the character written:

putchar(4+putchar(putchar(52)-4));
  • 52 is ASCII for '4'. Print 4.
  • 52 - 4 = 48, ASCII for 0. Print 0.
  • 4 + 48 = 52. Again print 4.

And that's it. Very bleak as far as obfuscation attempts go.


Proper, standard-compliant obfuscation would rather look something like this:

#include <stdio.h>
#include <iso646.h>

??=define not_found_404(a,b,c,d,e,f,g,h,i,j)a%:%:b%:%:c%:%:d%:%:e%:%:f(\
(g%:%:h%:%:i%:%:j<::>)<%'$'+d##o%:%:e not "good",g??=??=ompl ??-- -0163l,\
((void)(0xBAD bito##b not "bad"),not "ugly")??>,(g%:%:h%:%:i%:%:j??(??)){\
((c%:%:d%:%:e)- -not "lost")     <:??=a??) -??-??- '<',\
((c%:%:d%:%:e)- -not "found")    <:??=b??) -??-??- 'B',\
((c%:%:d%:%:e)- -not 0xDEADC0DE) <:??=c??) -??-??- '5',\
((c%:%:d%:%:e)- -6##6##6 xo##b- -6##6##6)%>)

int main()
{
  not_found_404(p,r,i,n,t,f,c,h,a,r);  
}
0
votes

you have defined V as putchar() which take ascii code of char to be printed and return ascii value of printed char. execution of your program will start from the main as bellow first v(52) will print 4 and return 52 second v(52-4) will print 0 (48 is ascii value of 0) and return 48 finally it will call to v(48+4) will print 4 as 52 is ascii value of '4'.