【问题标题】:How does this code print 404?此代码如何打印 404?
【发布时间】:2017-12-01 08:26:26
【问题描述】:

我从 Stack Overflow 的 404 Not Found Error Page 复制了以下代码。

# define v putchar
# define print(x)
main(){v(4+v(v(52)-4));return 0;}/*
#>+++++++4+[>++++++<-]>
++++.----.++++.*/
print(202*2);exit();
#define/*>.@*/exit()

上面的代码编译良好并在控制台上打印 404。我以为语句 print(202*2); 负责打印 404,但我不对,因为更改此语句中的数字也会打印 404。

谁能帮我理解这段代码以及它如何打印404

我发布编译输出供您参考,因为有 cmets 说此代码无法编译。包含上述代码的文件是Test.c

gcc Test.c -o 测试

Test.c:3:1:警告:返回类型默认为“int”[-Wimplicit-int] main(){v(4+v(v(52)-4));return 0;}/* ^ Test.c: 在函数'main'中: Test.c:1:12:警告:函数“putchar”的隐式声明 [-Wimplicit-function-declaration] # 定义 v putchar ^ Test.c:3:8: 注意: 在宏'v' main(){v(4+v(v(52)-4));return 0;}/* 的扩展中 ^ Test.c:在顶层:Test.c:6:14:警告:数据定义没有类型或存储类 print(202*2);exit(); ^ Test.c:6:14:警告:在“退出”的声明中类型默认为“int” [-Wimplicit-int] Test.c:6:14:警告: 内置函数“exit”的类型冲突

./测试

404

【问题讨论】:

  • putchar(52) 输出 4; 52-4 = 48; putchar(48) 输出 0; 48+4 = 52; putchar(52) 再次输出 4。
  • 只是问:亲爱的移民到 MSO 选民:你能补充一点理由吗?我想我在这里遗漏了一些关于为什么应该迁移的内容?
  • @SouravGhosh;它应该被迁移,因为它已在 meta stackoverflow 上被询问过,并且已经有一些很好的答案。
  • @Beginner 不,如果不重写大部分内容,就不可能在符合标准的 C 编译器上编译它。

标签: c gcc


【解决方案1】:

不能使用元问题作为欺骗,所以公然抄袭the MSO answer

由于这被标记为 并提到“已编译”,因此只需提取其中的 C 部分。

致谢:Mark Rushakofforiginal author of the polyglot

C 代码相当容易阅读,但如果你运行它会更容易 通过预处理器:

main(){putchar(4+putchar(putchar(52)-4));return 0;};exit();

您的标准 main 函数在那里声明,exit 也是 声明为隐式返回类型为 int (exit 被有效地忽略)。

putchar 被使用是因为你不需要任何#include 来使用它; 你给它一个整数参数,它会放入相应的 ASCII 字符到标准输出并返回您给它的相同值。所以,我们 放 52(即4);然后我们减去 4 并输出0;然后我们添加 4 再次输出4

还有一点,来自 [Cole Johnson's] (https://meta.stackoverflow.com/users/1350209/cole-johnson)answer

忽略所有这些,当我们重新格式化代码并替换 52 及其 ASCII 等价物 ('4'),我们得到:

int main() {
    putchar(4 + putchar(putchar('4') - 4));
    return 0;
}

至于putchar声明,标准定义为 返回它的输入,例如realloc。首先,这个程序打印一个4, 然后取 ASCII 值 (52),减去 4 (48),打印 (ASCII 0),加 4 (52),打印 (4),最后 终止。这会产生以下输出:

404

至于这个多语言是有效的C++,不幸的是,它不是 C++ 需要函数的显式返回类型。这个程序利用了 C 需要没有 显式返回类型为int

【讨论】:

  • 那么应该投票支持转移到 meta 上。可以作为副本关闭的地方。
  • @StoryTeller 但它在 SO 中的一个有效问题。这是关于代码理解,而不是关于 SO 的工作......对吗?我知道上下文是重叠的,但这里也不是 OT……你怎么看?
  • 我同意这是一个有效的主题,所以 ^^。也许做一个维基答案。事实上,这是题外话的元问题。
  • 我认为我们不应该一遍又一遍地回答问题。这与元重叠,元有一个完美的答案。
  • 如果代码曾经有可能在“The Real World™”中遇到,那么它应该留在这里。鉴于代码的 SO 特殊性,Meta 可能是它的地方。
【解决方案2】:
# define v putchar

这将v 定义为putchar() 函数。它打印一个字符并返回它。

# define print(x)

这将print(x) 定义为空(所以print(202*2) 表示空)

main(){v(4+v(v(52)-4));return 0;}/*

这可以重写为:

main()
{
  putchar(4 + putchar(putchar(52) - 4));
  return 0;
}

它使用 ASCII 代码来打印“4”(代码 52)、“0”(代码 52 - 4 = 38)和“4”,因此是“404”。

该行以/* 结尾,开始注释并继续接下来的两行:

#>+++++++4+[>++++++<-]>
++++.----.++++.*/

下面的行是空的,但有点棘手,因为exit() 被定义为空AFTER 行本身。这是因为 C 预处理器在编译之前运行

print(202*2);exit();

下面的行将exit() 定义为空,用于上面的行。

#define/*>.@*/exit()

【讨论】:

    【解决方案3】:

    代码无法在标准 C 编译器上编译,例如 gcc -std=c11 -pedantic-errors

    1) main 在托管系统上必须返回 int。
    2) putchar() 必须有#include &lt;stdio.h&gt;.
    3) 不能在函数外写分号。

    在修复了这些初学者级别的错误并删除了所有只会造成编译器错误的多余绒毛之后,我们只剩下以下内容:

    #include <stdio.h>
    #define v putchar
    int main(){v(4+v(v(52)-4));return 0;}
    

    这围绕 putchar 返回写入的字符:

    putchar(4+putchar(putchar(52)-4));
    
    • 52 是'4' 的 ASCII。打印 4。
    • 52 - 4 = 48,0 的 ASCII 码。打印 0。
    • 4 + 48 = 52。再次打印 4。

    就是这样。就混淆尝试而言,非常惨淡。


    适当的、符合标准的混淆应该是这样的:

    #include <stdio.h>
    #include <iso646.h>
    
    ??=define not_found_404(a,b,c,d,e,f,g,h,i,j)a%:%:b%:%:c%:%:d%:%:e%:%:f(\
    (g%:%:h%:%:i%:%:j<::>)<%'$'+d##o%:%:e not "good",g??=??=ompl ??-- -0163l,\
    ((void)(0xBAD bito##b not "bad"),not "ugly")??>,(g%:%:h%:%:i%:%:j??(??)){\
    ((c%:%:d%:%:e)- -not "lost")     <:??=a??) -??-??- '<',\
    ((c%:%:d%:%:e)- -not "found")    <:??=b??) -??-??- 'B',\
    ((c%:%:d%:%:e)- -not 0xDEADC0DE) <:??=c??) -??-??- '5',\
    ((c%:%:d%:%:e)- -6##6##6 xo##b- -6##6##6)%>)
    
    int main()
    {
      not_found_404(p,r,i,n,t,f,c,h,a,r);  
    }
    

    【讨论】:

    • “你不能在函数之外写分号。”,什么?你的意思是指令?顺便说一句,main() 的原型在这种情况下应该是 int main(void);,所以你不符合要求:p。
    • @Stargateur print(202*2);exit(); 被解释为 ;exit(); 这是无稽之谈。 GCC 给出错误“ISO C 不允许额外的 ';'在函数之外”。不, main() 的形式可以采用任何参数,并且标准不是很清楚。 stackoverflow.com/a/31263079/584518
    • 这不是混淆尝试。这是一个多语言代码。
    • @bolov 不,不是,如上所示。多语言是可以用多种语言编译的代码。
    • @Lundin meta.stackexchange.com/a/27846/254429 它在 Befunge-93、Brainf*ck、Python、Ruby、Perl 和 C 中运行并具有相同的输出。Okey 我明白你的意思不是标准 C,但仍然如此。 ..
    【解决方案4】:

    您已将 V 定义为 putchar(),它采用要打印的 char 的 ascii 代码并返回打印的 char 的 ascii 值。您的程序的执行将从 main 开始,如下所示 第一个 v(52) 将打印 4 并返回 52 第二个 v(52-4) 将打印 0(48 是 0 的 ascii 值)并返回 48 最后它将调用 v(48+4) 将打印 4,因为 52 是 '4' 的 ascii 值。

    【讨论】:

      猜你喜欢
      • 2017-02-28
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      相关资源
      最近更新 更多