helloB
helloB

Reputation: 3582

How does this quine work?

I just came across this quine question, but no one really went into how it works: C/C++ program that prints its own source code as its output

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}

What I especially don't understand is the following has the same output even though I changed the ints:

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,5,s,11);}

It still prints the 34s! Can someone walk me through this step by step?

Upvotes: 1

Views: 1795

Answers (1)

templatetypedef
templatetypedef

Reputation: 372784

Let's start by formatting the code to span multiple lines. This breaks the fact that it's a quine, but makes it easier to see what's happening:

char* s = "char*s=%c%s%c;main(){printf(s,34,s,34);}";

main() { 
   printf(s, 34, s, 34);
}

Essentially, this is a declaration of a string s that's a printf-formatted string, followed by a declaration of a function main that invokes printf on four arguments. (This definition of main uses the old-fashioned "implicit int" rule in C where functions are assumed to have int as a return type unless specified otherwise. I believe this is currently deprecated in C and know for certain that this is not legal C++ code.)

So what exactly is this printf call doing? Well, it might help to note that 34 is the ASCII code for a double-quote, so the line

printf(s, 34, s, 34);

is essentially

printf(s, '"', s, '"');

This means "print the string s with arguments ", s, and "." So what's s? It's shown here:

char* s = "char*s=%c%s%c;main(){printf(s,34,s,34);}";

This follows a common self-reference trick. Ignoring the %c%s%c part, this is basically a string representation of the rest of the program. The %c%s%c part occurs at the point where it becomes self-referential.

So what happens if you call printf(s, '"', s, '"')? This will fill in the placeholder %c%s%c with "char*s=%c%s%c;main(){printf(s,34,s,34);}", which is the string contents of the string s. Combined with the rest of the string s, this therefore proints

char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);";

which is the source code of the program. I think this is kinda neat - the closest English translation of a general Quine program I know is "print this string, the second time in quotes" (try it - see what happens!), and this basically does exactly that.

You were asking why changing the numbers to 5 and 11 didn't change that 34 was being printed. That's correct! The string literal s has 34 hard-coded into it, so changing the 5 and 11 in the call to printf won't change that. What it will do is no longer print the quotation marks around the inside of the string s and instead print non-printing characters.

Upvotes: 11

Related Questions