0

In my course slides, I have this example but without much explanation:

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

I understand what quine programs in general mean but I do not quite understand what's happening in the code above. This is the output I get if I run it:

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

But how is it reproducing its own code? I don't really understand how the output is produced.

Edd Inglis
  • 1,067
  • 10
  • 22
x89
  • 2,798
  • 5
  • 46
  • 110
  • "If I try to compile it, I get a segmentation fault." If you get a segfault while compiling, that's a compiler error. Do you mean that you get an error when you run it? – Thomas Jager Feb 13 '20 at 16:44
  • Also, this isn't a complete program in modern C. GCC will however (un)happily compile it, and seems to run as expected. – Thomas Jager Feb 13 '20 at 16:45
  • 1
    @ThomasJager I know it's not a complete code but I copied it as it is from my lecture notes and I am just trying to understand the functionality. I tried running it online (after putting it into int main()) but got a segmentation fault (core dumped), so yes an error. – x89 Feb 13 '20 at 16:49
  • This is the entire program. You're not going to be able to use it if you put it within another function. Are you changing anything else (like adding a semicolon after `main()`) when you're putting it in something else? See https://godbolt.org/z/Nd8Gmb – Thomas Jager Feb 13 '20 at 16:50
  • Is this the sort of thing they're teaching you kids these days?! – Edd Inglis Feb 13 '20 at 16:51
  • @EddInglis Yes, why? It's the Secure & Dependable Systems course. – x89 Feb 13 '20 at 17:00
  • 3
    Well it was partly meant as a joke, but with a serious point: _IMO_ this is the sort of thing you offer students as an end-of-term fun puzzle, not something "in the course slides". Life is too short for this sort of nonsense, particularly since you've evidently not been taught enough yet to make sense of it. – Edd Inglis Feb 13 '20 at 17:06
  • @EddInglis _Life is too short for /* actually many*/ sort of nonsense_ liked it. +1 :-) – some user Feb 13 '20 at 17:08

1 Answers1

4

Start by writing it out in a way that'll be clearer (not changing anything but the layout):

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

main()
{
    printf(f,34,f,34,10);
}

So we see a main function as we'd expect (it should return an int but you're allowed to get away with not in C; likewise for no function arguments). And before that, a regular string. It's a funny-looking string, but it is not really that different to char*f="fish";.

Okay, so what if we expand the printf by putting the string in there by hand?

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

We can see that it's going to print out some guff, and substitute in some values along the way. They are:

 First %c : 34   (the ASCII code for " (quotes))
 First %s : 'f'  (our string, once again)
Second %c : 34   (" again) 
 Third %c : 10   (the ASCII code for Newline)

Let's substitute those all in then too (though I've replaced the contents of the string with <the string>, and "'s with \"'s to make it actually work as a standalone statement):

main()
{
    printf("char*f=\"<the string>\";main(){printf(f,34,f,34,10);}\n");
}

Well look at that! main simply prints out the line we first started with. Hurrah!


Edited to add:

Although I've basically spelled out the answer for you, there is still a puzzle remaining. Consider for yourself why we bother substituting in the 34, f, 34, 10, rather than just putting them directly into the string like I did in my final code.

Edd Inglis
  • 1,067
  • 10
  • 22
  • 1
    This is a valid but not a strictly conforming c89 program. It is however invalid in modern c where modern means less than 20 years old – Antti Haapala -- Слава Україні Feb 13 '20 at 17:17
  • Thanks for the explanation! I simply thought its to explain how this works. Is it because if we just put them directly into the string, they'll be read as strings in the first place and we wouldn't be able to use their values for other purposes? (If the code had other parts)? – x89 Feb 13 '20 at 17:33
  • Not quite. If you want the output to include quote marks, you need to print them out. But you can't just put them in the string, because that'll end the string early. So you have to escape them (as I did). But then you have to print out the escape characters, which themselves need escaping and so on and so on! – Edd Inglis Feb 13 '20 at 21:27