Quine

  • Notes on a quine written in C

What is it

A program that prints itself (its own source code).

Implement

Here is an implementation written in C, inspired by Tsoding.

q.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>

int main() {
char* ancher = "#include <stdio.h>\n\nint main() {\n char* ancher = \"?\";\n for (int i = 0; ancher[i]; i++) {\n if (ancher[i] == 63) {\n for (int j = 0; ancher[j]; j++) {\n switch (ancher[j]) {\n case '\\n':\n printf(\"\\\\n\");\n break;\n case '\"':\n printf(\"\\\\\\\"\");\n break;\n case '\\\\':\n printf(\"\\\\\\\\\");\n break;\n default:\n printf(\"%c\", ancher[j]);\n }\n }\n } else {\n printf(\"%c\", ancher[i]);\n }\n }\n return 0;\n}";
for (int i = 0; ancher[i]; i++) {
if (ancher[i] == 63) {
for (int j = 0; ancher[j]; j++) {
switch (ancher[j]) {
case '\n':
printf("\\n");
break;
case '"':
printf("\\\"");
break;
case '\\':
printf("\\\\");
break;
default:
printf("%c", ancher[j]);
}
}
} else {
printf("%c", ancher[i]);
}
}
return 0;
}

The content of ancher can be generated by this NodeJs script

1
2
3
4
5
6
7
8
9
10
import { readFileSync } from 'node:fs';

const str = readFileSync("q.c").toString();

for (let c of str) {
if (c === '\n') process.stdout.write("\\n");
else if(c == '"') process.stdout.write("\\\"");
else if(c == '\\') process.stdout.write("\\\\");
else process.stdout.write(c);
}

Mostly, it just escapes , ” and  from the source code into string form.

How it works

The most convenient way to do that is using file system, we just read the source file.

But how can we reach this goal without using outside information ?

We can gradually make it.

Ancher

Assume an string variable which is ancher that contain the source code we need to print, but now we only put a question mark to it.

question mark
1
2
3
4
5
6
7
#include <stdio.h>

int main() {
char* ancher = "?";
printf("%s",ancher);
return 0;
}

So we could only see a ? on the screen right now.

Escape once

We put the actual source code to the ancher

You can use the js code mentioned to escape the whole source code.

question mark
1
2
3
4
5
6
7
#include <stdio.h>

int main() {
char* ancher = "#include <stdio.h>\n\nint main() {\n char* ancher = \"?\";\n printf(\"%s\", ancher);\n return 0;\n}";
printf("%s",ancher);
return 0;
}

Now the output looks a little bit closer.

output
1
2
3
4
5
6
7
#include <stdio.h>

int main() {
char* ancher = "?";
printf("%s", ancher);
return 0;
}

In the source code, the ancher is fill with escaped text, but we only got a ? when output.

Let’s take a closer look. What’s the difference? What if we could make ? be the text in the ancher?

We only need to repeat it once.

Replace once

When output, if current char is ?, then we replace it with the text in the ancher

replace the question mark
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main() {
char* ancher = "#include <stdio.h>\n\nint main() {\n char* ancher = \"?\";\n for (int i = 0; ancher[i]; i++) {\n if (ancher[i] == '?') {\n printf(\"%s\", ancher);\n } else {\n printf(\"%c\", ancher[i]);\n }\n }\n return 0;\n}";
for (int i = 0; ancher[i]; i++) {
if (ancher[i] == '?') {
printf("%s", ancher);
} else {
printf("%c", ancher[i]);
}
}
return 0;
}

Now, does it look identical to the original source code?

output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>

int main() {
char* ancher = "#include <stdio.h>

int main() {
char* ancher = "?";
for (int i = 0; ancher[i]; i++) {
if (ancher[i] == '?') {
printf("%s", ancher);
} else {
printf("%c", ancher[i]);
}
}
return 0;
}";
for (int i = 0; ancher[i]; i++) {
if (ancher[i] == '#include <stdio.h>

int main() {
char* ancher = "?";
for (int i = 0; ancher[i]; i++) {
if (ancher[i] == '?') {
printf("%s", ancher);
} else {
printf("%c", ancher[i]);
}
}
return 0;
}') {
printf("%s", ancher);
} else {
printf("%c", ancher[i]);
}
}
return 0;
}

No, it doesn’t. What’s the difference? It print twice and there is no escape of \n, \ and ", they are all be the real control characters

Why twice? Because there are two ? in the text, we check the question mark by ?, that’s easy to fix, we could use the ascii of ?, which is

But how could we solve the escape issue? Notable thing is, we don’t want the escape happened in the text part rather than the normal code part.

So we need to manually do the replacing part. It’s basically what the js code do.

Escape twice

Now the code is identical to the code shown earlier in the Implement section.

What’s next

Yes, there are many other ways, and may transform from one language to another then back to the original, which is quine relay.

quine-relay there is an implement of 128 language quine relay

But the method in this article can be use for other languages to make a single quine. It feels very much like a “Whack-a-Mole” game: fixing one problem causes another to appear.