3

我在 Ken Thompson 的一篇文章(阅读此处)中看到的这个 quine并没有重现相同的代码。我只是好奇为什么它不起作用?代码现在过时了吗?

奎因代码:

char s[] = {
        '\t',
        '0',
        '\n',
        '}',
        ';',
        '\n',
        '\n',
        '/',
        '*',
        '\n'
};

/*
 *The string s is a representation of the body
 *of this program from '0'
 * to the end
 */

main(){
        int i;

        printf("char\ts[] = {\n");
        for(i = 0; s[i]; i++)
                printf("\t%d, \n", s[i]);
        printf("%s",s);
}

输出:

char    s[] = {
        9,
        48,
        10,
        125,
        59,
        10,
        10,
        47,
        42,
        10,
        0
};

/*

这些是编译时的编译器警告(self_reproducing.c是文件名):

self_reproducing.c:20:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
   20 | main(){
      | ^~~~
self_reproducing.c: In function ‘main’:
self_reproducing.c:23:2: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
   23 |  printf("char\ts[] = {\n");
      |  ^~~~~~
self_reproducing.c:23:2: warning: incompatible implicit declaration of built-in function ‘printf’
self_reproducing.c:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
  +++ |+#include <stdio.h>
    1 | char s[] = {

哎呀!我忽略了这213 lines deleted条线。所以问题应该是——<strong>文章中提到的整个 quine 是什么?

4

4 回答 4

2

我认为“不工作”的意思是不“给出编译器警告”——因为这些原因是不言而喻的——而是你写的其他内容:

这个 quine [...] 没有复制相同的代码

quine自我复制的,一旦我们添加回(213 lines deleted)作者删节的内容并且您删除了 - 这代表了其余的代码,加上0结束数组的 NUL 终止符chars

/*
 * The string s is a representation of the body
 * of this program from '0'
 * to the end
 */

您的困惑似乎源于程序如何打印所述数组中字符的整数 ASCII 值,但它最初声明了这些字符,如'\t','\n'等。但是具有适当值的整数是有效char的,因此代码自我复制的,即使元素被格式化为整数而不是'c'原始源中的字符。无论哪种方式,我们最终都会得到一个相同char的数组;只是该数组以不同但等效的方式初始化。

为什么将它们打印为整数?因为这比必须为每个元素引用、有条件地转义等要容易/短得多。它映射到相同的机器代码/数组内容,但需要更少的 faff 来编程 quine。

作者竟然写了这个!

(纯粹主义者会注意到,该程序并不完全是一个自我复制的程序,而是会产生一个自我复制的程序。)

至于编辑/添加的问题,整个 quine 当然会添加代表程序其余部分所需的其余字符。作者大概是为了能够更容易地说明他们的观点而对程序进行了删节,而不是通过一整页来驱动它。

于 2020-07-01T15:12:14.417 回答
2

代码序列'/', '\t','\n'等只是用来告诉编译器使用什么字符代码的助记符。它使我们不必为它们查找 ASCII 代码。对于某些控制代码,尤其是回车和换行符,实际代码取决于体系结构,因此这些助记符也可以使代码跨操作系统移植。然而,这篇文章的重点不是关于编写 quine 的,而是关于系统可以多么容易地被操作和维护它们的编码人员入侵,而不会留下任何明显的足迹。

上下文在这里很重要。Thomson 正在攻击一个老式的 Unix 系统,该系统不太可能在今天存在的任何东西上运行。


从参考文章:

在大学里,在电子游戏之前,我们会通过摆出编程练习来自娱自乐。最喜欢的方法之一是编写最短的自我复制程序。

“自我复制程序”没有提及复制它自己的源代码。

于 2020-07-01T15:40:59.733 回答
1

我在 Ken Thompson 的一篇文章(阅读此处)中看到的这个 quine 没有复制相同的代码。我只是好奇为什么它不起作用?

它没有给出预期的输出,因为它并不是“quine”的可重复示例。

引用肯自己关于“quine”的定义(强调我的):

更准确地说,问题是编写一个源程序,在编译和执行时,将产生其源代码的精确副本作为输出

显示的代码不会复制其整个源代码的精确副本作为输出,因为它并不意味着这样做。

肯甚至承认自己(强调我的):

图 1 显示了 C 编程语言中的一个自复制程序。(纯粹主义者会注意到,该程序并不完全是一个自复制程序,而是会产生一个自复制程序。)这个条目太大了,无法取胜一个奖品,但它展示了这项技术,并具有我完成我的故事所需的两个重要属性:......

213 lines deletedKen 的代码也证明了这一点。

它只是为了演示一个“quine”程序应该是什么,它的目的是打印它的源代码。


代码现在过时了吗?

除此之外,代码缺少部分,将其归类为严格的“quine”,

是的,代码现在已经过时了。它是在 1984 年制造的,当时 C 甚至还没有被 ANSI 标准化,并且用于像我们今天拥有的完全不同的机器。

您收到的警告证明了这一点。

要在没有警告并包含头文件的情况下编译此代码stdio.h,您需要一个std=c89支持函数隐式声明的编译器(或适当的编译器选项,如 fe),printf()自 C99(当前标准为 C18)以来不再支持该函数。

请注意,编译器/链接器可能仍然会printf()正确链接到定义,但它是一个过时的功能并且不符合现代标准。

此外,main()不再支持该表示法。如果没有将参数int main (void)传递int main()给.main()main()

*返回类型可以不同,但​​必须与int.


文章中提到的整个 quine 是什么?

这只是“quine”的一个例子。没有公开的完整原始示例。也许原件睡在档案馆的任何地方。但是如果你遵循每段代码都需要输出的准则,你可以自己开发它。


参考“对信任信任的反思”,Ken Thompson,1984 年 8 月:

于 2020-07-01T15:36:54.830 回答
0

您很可能没有包含“<stdio.h>”库。

只需添加

    #include <stdio.h>

在您的代码之上。

在您的编译器错误中建议使用相同的解决方案

于 2020-07-01T15:00:29.120 回答