如果没有循环或条件语句从1到1000打印的C代码如何工作?

obo*_*obo 148 c function-pointers

我发现C代码打印从1到1000没有循环或条件:但我不明白它是如何工作的.任何人都可以通过代码解释每一行吗?

#include <stdio.h>
#include <stdlib.h>

void main(int j) {
  printf("%d\n", j);
  (&main + (&exit - &main)*(j/1000))(j+1);
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*Mat 264

不要写那样的代码.


因为j<1000,j/1000为零(整数除法).所以:

(&main + (&exit - &main)*(j/1000))(j+1);
Run Code Online (Sandbox Code Playgroud)

相当于:

(&main + (&exit - &main)*0)(j+1);
Run Code Online (Sandbox Code Playgroud)

这是:

(&main)(j+1);
Run Code Online (Sandbox Code Playgroud)

哪个电话mainj+1.

如果j == 1000,则相同的行显示为:

(&main + (&exit - &main)*1)(j+1);
Run Code Online (Sandbox Code Playgroud)

归结为

(&exit)(j+1);
Run Code Online (Sandbox Code Playgroud)

哪个是exit(j+1)离开程序的.


(&exit)(j+1)并且exit(j+1)基本上是相同的 - 引用C99§6.3.2.1/ 4:

函数指示符是具有函数类型的表达式.除非它是sizeof运算符或一元&运算符的操作数,否则将具有" 函数返回类型 " 类型的函数指示符转换为具有" 指向函数返回类型的指针 "类型的表达式.

exit是一个功能指示符.即使没有一元&地址运算符,它也被视为指向函数的指针.(这&只是明确的.)

函数调用在§6.5.2.2/ 1及以下内容中描述:

表示被调用函数的表达式应具有指向函数的类型指针,该函数返回void或返回除数组类型之外的对象类型.

因此,exit(j+1)因为函数类型自动转换为指向函数类型的函数,所以(&exit)(j+1)可以正常工作,并且可以显式转换为指向函数的指针类型.

话虽这么说,上面的代码不符合(main两个参数或根本没有)&exit - &main,我相信,根据§6.5.6/ 9,它是未定义的:

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; ...

加入(&main + ...)将是自身有效的,并且可以使用,如果在添加量是零,因为§6.5.6/ 7说:

出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型.

因此,添加零&main就可以了(但没有多大用处).

  • 不必要的复杂,至少对于C99:`((void(*[])()){main,exit})[j/1000](j + 1);` (8认同)
  • `foo(arg)`和`(&foo)(arg)`是等价的,他们用参数arg调用foo.http://www.newty.de/fpt/fpt.html是一个关于函数指针的有趣页面. (4认同)

tda*_*ers 41

它使用递归,指针算法,并利用整数除法的舍入行为.

j/1000对于所有人来说j < 1000,这个词总计为0 ; 一旦j达到1000,则评估为1.

现在,如果你有a + (b - a) * n,n0或1,你最终得到aif n == 0bif n == 1.使用&main(地址main())和&exit用于ab的,术语(&main + (&exit - &main) * (j/1000))返回&mainj是低于1000,&exit否则.然后,生成的函数指针被赋予参数j+1.

整个结构导致递归行为:当j低于1000时,main递归调用自身; 当j达到1000时,它调用exit,使程序退出,退出代码为1001(这有点脏,但有效).

  • 当j达到1000时,main不会再进入自身; 相反,它调用libc函数`exit`,它将退出代码作为其参数,并且退出当前进程.此时,j为1000,因此j + 1等于1001,这将成为退出代码. (2认同)