Reputation: 3582
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
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