打印“你好世界!”在C中使用read

时间:2013-06-08 12:45:10

标签: c

我在ioccc中看到了这一点。

    int i;
    main()
    {
        for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hello, world!\n",'/'/'/'));
    }
    read(j,i,p)
    {
        write(j/p+p,i---j,i/i);
    }

打印出“你好世界!”使用gcc编译时,不确定它是否适用于visual studio 12。 有人可以向我解释它是如何运作的吗?

3 个答案:

答案 0 :(得分:4)

由于原始代码已从问题中删除并重新格式化,因此我将替换为主题启动程序提供的代码。

  

int i;main(){for(;i["]<i;++i){--i;}"];
  read('-'-'-',i+++"hello, world!\n",'/'/'/'));
  }read(j,i,p){write(j/p+p,i---j,i/i);}

从恢复结构开始。添加它们所属的空格和换行符。请记住,未指定时,C假定int数据类型。

int i;

/* int */ main()
{
  for( ; i["]<i;++i){--i;}"];
          read(   '-' - '-',
                   i++ + "hello, world!\n",
                   '/' / '/') );
}

/* int */ read( /* int */ j,i,p)
{
  write( j/p + p, i-- - j, i/i );
}

注意用C语言:

  1. 没有“字符”类型。字母只是一个(通常是8位)整数。因此'-' - '-'为零且'/' / '/'为1(后面就像i/i一样)
  2. 没有“字符串”类型 - 这只是指向“字符”的指针
  3. 数组和指针根据定义是相同的
  4. 无大小(字节大小)的指针和整数隐式转换为彼此。
  5. 注意:在下面的评论中,人们认为在C数组中不是指针,而是隐含地指向指针。这在理论上可能是正确的,但似乎对这个特定代码没有任何实际意义。但是,一本子弹3可能也被书籍错误地制定了。

    另外,让我们假设所有全局变量都是零初始化的。

    因此i["]<i;++i){--i;}"]为0 [指向某个字符串的指针],然后是1 [指向某个字符串的指针],等等。实际上是字符串的第i个字符。
    它用于第二个参数位置的for循环 - 条件检查器。所以实际上这可以重新制定为

    for( ; "]<i;++i){--i;}"[i] != '\0'; read... );

    或根据C for loop的定义

    while ( "]<i;++i){--i;}"[i] != 0 ) { read ...; }

    两条线都有14个字符,这不是一个证据:
    "hello, world!\n"
    "]<i;++i){--i;}"

    这使得它只是字符串中每个字符的循环,您可以将其重新表示为
     for i := 0 to 14-1 do

    将这一切粘在一起,程序变成

    int i;
    
    /* int */ main()
    {
      for( i=0; i<strlen("hello, world!\n"); i++)
      {
        read( 0, & "hello, world!\n"[i], 1);
      }
    }
    

    有点容易吗?现在转移到函数本身...和C文件句柄。根据UNIX标准,预定义了以下文本文件:

    • 0 - STDIN - 从键盘上读取
    • 1 - STDOUT - 打印到显示/打印机/日志文件/等
    • 2 - STDERR - 关于错误情况的紧急打印

    因此:

    /* int */ read( j = 0, i = pointer-to-letter-to-print, p = 1)
    {
      write( j/p + p, // 0/1 + 1  == 1 == STDOUT 
             i-- - j, // == i itself due to j == 0; 
                      // -- is POST-decrement and does not affect the calculation
             i/i /*== 1 as long as i != 0  - meaning print only single character*/ );
    }
    

    再次粘合在一起:

    int i;
    
    int my_read( int j, char * pChar, int p)
    {
      write( STDOUT, pChar, 1 );
      pChar--; // does not affect anything, as mentioned above
    }
    
    const char msg[] = "hello, world!\n";
    int main(void)
    {
      for( i=0; i<strlen(msg); i++)
      {
        my_read( 0, &msg[i], 1);
      }
    }
    

    你能弄清楚这个片段现在如何运作吗? ; - )

    只需添加空格和新行 - 正确的代码结构格式化 - 它变得容易 - 俗气: - )

答案 1 :(得分:1)

  • '-'-'-'的结果是 0
  • '/'/'/'的结果是 1

    所以,read('-'-'-',i+++"hello, world!\n",'/'/'/'));

    实际上是

    read(0,i+++"hello, world!\n",1));

  • 关于循环:for(;i["]<i;++i){--i;}"];

    i["]<i;++i){--i;}"]

    实际上是

    "]<i;++i){--i;}"[i]

    因为在C中,如果你写a[i],它相当于i[a]*(a+i) == *(i+a)

    所以这个for循环将继续前进,直到遇到最后一个字符。

总而言之,理解这里发生的事情很容易。 (我在此链接中找到了更多解释:http://www.cs.washington.edu/education/courses/cse142/97su/josh/obfuscate.html

答案 2 :(得分:0)

让我们首先更好地格式化这个:

int i;


main()
{
   for(;i["]<i;++i){--i;}"];
       read('-'-'-',i++ + "hello, world!\n",'/'/'/'));
}


read(j,i,p)
{
  write(j/p+p,i---j,i/i);
}

其次,我们看看它实际上做了什么:

for(;i["]<i;++i){--i;}"];

相同
for(;"]<i;++i){--i;}"[i];

因此,没有初始化,并且只要i索引的“C代码”的字符串不为零。

然后是for循环的更新部分:

read('-'-'-',i++ + "hello, world!\n",'/'/'/'));

'-'-'-'就像'a'-'a'一样为零。 i++ + "hello, world!"是指针+偏移量,当然更新“i”。最后一部分是自己划分的东西,这就是1.

最后一招是重新定义的read函数,它调用write:

read(j,i,p)
{
  write(j/p+p,i---j,i/i);
}

它使用类似的技巧来生成stdout的值,其中j / p + p(从上面p = 1,j = 0,所以0/1 + 1 = 1)和数据的长度写(1)。要写的字符是i-- -j,因为我们在执行i之前采用--,它没有效果[它不是使用全局i,而是使用read本地的{{1}} {1}}。