采访 Hello World 解释

发布于 2024-09-25 12:15:12 字数 509 浏览 7 评论 0 原文

这个经典的ioccc条目是一个用C编写的Hello World程序。任何人都可以提供吗解释它是如何工作的?

原始代码(有意缺失的语法突出显示):

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

稍微干净一些:

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);
}

This classic ioccc entry is a Hello World program written in C. Can anyone please provide an explanation of how it works?

Original code (syntax highlighting intentionally missing):

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

Slightly cleaner:

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦一生花开无言 2024-10-02 12:15:12

for 循环条件

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

该表达式利用了 C 中数组索引是可交换的这一事实。它相当于。

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

因此,当位置 i 处的字符为 \0 时,循环将终止,即位于字符串末尾,长度为 14 个字符(恰好是相同的)长度为“你好,世界!\n”)。因此 for 循环条件可以重写为:

i != 14

字符算术

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

char 是整数类型,因此:

  • '-' - '-' 是0
  • '/' / '/' 为 1

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


修复所有编译器警告(例如隐式 int 到指针转换)并简化上述内容后,代码变为:(

#include <unistd.h>

int i = 0;

void read2(int, char*, int);

int main()
{
   while (i != 14)
   {
      read2(0, i++ + "hello, world!\n", 1);
   }

   return 0;
}

void read2(int j, char* i, int p)
{
   write(j / p + p, i-- - j, 1);
}

我将 read 重命名为 read2< /code> 以避免与 Unix read 函数冲突。)

请注意 read2jp 参数不需要,因为函数总是在 j=0 和 p=1 的情况下调用。

#include <unistd.h>

int i = 0;

void read2(char*);

int main()
{
   while (i != 14)
   {
      read2(i++ + "hello, world!\n");
   }

   return 0;
}

void read2(char* i)
{
   write(1, i--, 1);
}

调用 write(1, i--, 1)i 中的 1 个字符写入文件描述符 1 (stdout)。并且后递减是多余的,因为这个 i 是一个永远不会再次引用的局部变量。所以这个函数等价于putchar(*i)

在主循环中内联 read2 函数的

#include <stdio.h>

int i = 0;

int main()
{
   while (i != 14)
   {
      putchar(*(i++ + "hello, world!\n"));
   }

   return 0;
}

含义是显而易见的。

for loop condition

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

This expression takes advantage of the fact that array indexing is commutative in C. It is equivalent to.

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

So the loop will terminate when the character at position i is \0, i.e., at the end of the string, which is 14 characters long (which happens to be the same length as "hello, world!\n"). So the for loop condition can be rewritten as:

i != 14

character arithmetic

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

char is an integer type, and thus:

  • '-' - '-' is 0
  • '/' / '/' is 1

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


After fixing all the compiler warnings (like implicit int to pointer conversion), and simplifying the things mentioned above, the code becomes:

#include <unistd.h>

int i = 0;

void read2(int, char*, int);

int main()
{
   while (i != 14)
   {
      read2(0, i++ + "hello, world!\n", 1);
   }

   return 0;
}

void read2(int j, char* i, int p)
{
   write(j / p + p, i-- - j, 1);
}

(I renamed read to read2 to avoid conflicting with the Unix read function.)

Note that the j and p arguments to read2 are unneeded, as the function is always called with j=0 and p=1.

#include <unistd.h>

int i = 0;

void read2(char*);

int main()
{
   while (i != 14)
   {
      read2(i++ + "hello, world!\n");
   }

   return 0;
}

void read2(char* i)
{
   write(1, i--, 1);
}

The call write(1, i--, 1) writes 1 character from i to file descriptor 1 (stdout). And the postdecrement is superfluous because this i is a local variable never referenced again. So this function is equivalent to putchar(*i).

Inlining the read2 function within the main loop gives

#include <stdio.h>

int i = 0;

int main()
{
   while (i != 14)
   {
      putchar(*(i++ + "hello, world!\n"));
   }

   return 0;
}

for which the meaning is obvious.

往事风中埋 2024-10-02 12:15:12

不想完全拆开它,但有一些提示:

  • '-' - '-' 被混淆为 0
  • '/' / '/ ' 和 read() 中的 i / i 被混淆为 1

请记住 [] 是可交换的,即 i["]"] 相同(具有一个 char 数组并指向它的第 i 个元素)。字符串的内容无论如何都不重要,只有它的长度用于定义循环的迭代次数。任何其他相同长度的字符串(顺便说一下,与输出的长度相同......)都可以。经过该次数的迭代后,“string”[i] 返回终止字符串的空字符。零 == false,循环终止。

这样,剩下的事情应该就比较容易弄清楚了。

编辑:这些赞成票让我有足够的兴趣进一步研究这个问题。

当然,i++ + "Hello, world!\n""Hello, world!\n"[ i++ ] 相同。

codelark 已经指出 0 是 stdout 的 fid。 (为此给+1,而不是我。只是为了完整性而提及它。)

read() 中的 i 当然是本地的,即read()中的i--不会影响main()中的i。由于无论如何下面的 i / i 始终是 1,因此 -- 运算符根本不执行任何操作。

哦,告诉面试官解雇写这段代码的人。 它不会对 write() 的返回值进行错误检查。我可以忍受臭名昭著的写得很糟糕的代码(多年来一直如此),但不检查因为错误比坏更糟糕,这是错误。 :-)

剩下的只是一些三年级的数学。我会把它交给实习生。 ;-)

Not in a mind of taking this apart completely, but there are some hints:

  • '-' - '-' is obfuscated for 0
  • '/' / '/' and the i / i in read() are obfuscated for 1

Remember that [] is commutative, i.e. i["]<i;++i){--i;}"] is the same as "]<i;++i){--i;}"[i] (having a char array and pointing at the i'th element of it). The content of the string doesn't matter in any way, only its length is used to define the number of iterations of the loop. Any other string of the same length (incidentially, the same length as the output...) would work. After that number of iterations, "string"[i] returns the null character that terminates the string. Zero == false, loop terminates.

With that, it should be comparatively easy to figure out the rest.

Edit: The upvotes made me interested enough to look at this some more.

Of course, i++ + "Hello, world!\n" is the same as "Hello, world!\n"[ i++ ].

codelark already pointed out that 0 is the fid for stdout. (Give him +1 for that, not me. Just mentioning it for completeness.)

The i in read() is of course local, i.e. the i-- in read() does not affect the i in main(). Since the following i / i is always 1 anyway, the -- operator does nothing at all.

Oh, and tell the interviewer to fire whoever wrote this code. It does not do error checking on the return value of write(). I can live with notoriously badly-written code (and have, for many years), but not checking for errors is worse than bad, that's faulty. :-)

The rest is just some third-grade maths. I'd pass that to an intern. ;-)

爱要勇敢去追 2024-10-02 12:15:12

i["..."] 的字符串索引导致循环执行字符串的长度。
i++ + hello world 字符串意味着每次迭代都会将从更深的一个字母开始的字符串传递给本地读取函数。

第一次迭代=“你好..”
第二次迭代 = "ello.."

读取函数的第一个参数简化为 0,即 stdout 的文件描述符。最后一个参数简化为 1,因此每次调用仅写入一个字符。这意味着每次迭代都会写入传递到 stdout 的字符串的第一个字符。因此,遵循上面的示例字符串:

第一次迭代=“h”
第二次迭代 = "e"

for 循环中的字符串索引与 hello world 字符串的长度相同,并且由于 [] 是可交换的,并且字符串以 null 结尾,因此最后一次迭代将返回 null 字符并退出循环。

The string index of i["..."] causes the loop to execute for the length of the string.
i++ + the hello world string means each iteration passes the string starting one letter deeper to the local read function.

first iteration = "hello.."
second iteration = "ello.."

The read function's first parameter simplifies to 0, stdout's file descriptor. The last parameter simplifies to 1, so only one character is written per call. This means each iteration will write the first character of the string passed to stdout. So following the example strings from above:

first iteration = "h"
second iteration = "e"

The string index in the for loop is the same length as the hello world string, and as [] is commutative, and strings are null terminated, the last iteration will return the null character and exit the loop.

风启觞 2024-10-02 12:15:12

远不是 C 专家,但我会尝试:

i["]<i;++i){--i;}"]
// is actually
char* x = "]<i;++i){--i;}"
*(i + x)
// and will turn to zero when i == 14 (will point to string's ending zero)
// '-' - '-' and '/' / '/' are always 0 and 1
// int i is initiated to zero
// i++ will return original value, so main turns to
main()
{
    char* hello = "hello, world!\n";
    for (i = 0 ; i != 14; i++) read(0, hello[i], 1);
}

// read becomes
// i-- does nothing here, i is in read's scope, not the global one
read(j, i, p)
{
  write(1, i, 1);
}

// and at last
main()
{
    char* hello = "hello, world!\n";
    for (i = 0 ; i<14; i++) write(1, hello[i], 1);
}

Far from C expert, but I'll try:

i["]<i;++i){--i;}"]
// is actually
char* x = "]<i;++i){--i;}"
*(i + x)
// and will turn to zero when i == 14 (will point to string's ending zero)
// '-' - '-' and '/' / '/' are always 0 and 1
// int i is initiated to zero
// i++ will return original value, so main turns to
main()
{
    char* hello = "hello, world!\n";
    for (i = 0 ; i != 14; i++) read(0, hello[i], 1);
}

// read becomes
// i-- does nothing here, i is in read's scope, not the global one
read(j, i, p)
{
  write(1, i, 1);
}

// and at last
main()
{
    char* hello = "hello, world!\n";
    for (i = 0 ; i<14; i++) write(1, hello[i], 1);
}
笔芯 2024-10-02 12:15:12

另一个面试问题似乎更多地反映了面试官而不是受访者。
这里的关键问题:
* j 始终为 0 (('-' - '-') == 0)
* p 始终为 1 (('/' / '/') == 1)
* i(在 read 函数中)是 (i++ + "hello world") == hello world 中的第 i 个字符(然后递增 i)

因此 read 函数变为

read(0, NextChar, 1)
{
  write(1, NextChar , 1);
}

唯一的其他位是 [] 运算符的交换律for 循环。

恕我直言,理解和解析这种代码确实毫无价值。

Yet another interview question that seems to reflect more on the interviewer than the interviewee.
Key issues here:
* j is always 0 (('-' - '-') == 0)
* p is always 1 (('/' / '/') == 1)
* i (in the read function) is (i++ + "hello world") == the i'th character in hello world (then increment i)

Thus the read function becomes

read(0, NextChar, 1)
{
  write(1, NextChar , 1);
}

The only other bit is the commutativity of the []operator in the for loop.

Understanding and parsing this kind of code is really valueless imho.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文