从1到1000打印没有循环或条件语句的C代码是如何工作的?
我发现C
代码打印从1到1000没有循环或条件 :但我不明白它是如何工作的。 任何人都可以通过代码并解释每一行?
#include <stdio.h> #include <stdlib.h> void main(int j) { printf("%d\n", j); (&main + (&exit - &main)*(j/1000))(j+1); }
不要这样写代码。
对于j<1000
, j/1000
是零(整数除法)。 所以:
(&main + (&exit - &main)*(j/1000))(j+1);
相当于:
(&main + (&exit - &main)*0)(j+1);
这是:
(&main)(j+1);
哪个调用j+1
main
。
如果j == 1000
,那么相同的线出来:
(&main + (&exit - &main)*1)(j+1);
归结到
(&exit)(j+1);
这是exit(j+1)
并离开程序。
(&exit)(j+1)
和exit(j+1)
基本上是相同的东西 – 引用C99§6.3.2.1/ 4:
函数指示符是具有函数types的expression式。 除了sizeof运算符或一元运算符的操作数外,types为“ 函数返回types ”的函数标识符被转换为types为“ 指向函数返回types的指针 ”的expression式。
exit
是一个函数标识符。 即使没有一元操作符&
地址操作符,它也被视为一个指向函数的指针。 ( &
只是使其明确。)
函数调用在§6.5.2.2/ 1和下面描述:
表示被调用函数的expression式应该有指向返回void的函数的types指针,或者返回除数组types以外的对象types。
因此, exit(j+1)
是因为函数types自动转换为指针函数types,并且(&exit)(j+1)
工作得很好,并且显式转换为指针函数types。
这就是说,上面的代码是不符合( main
采取两个参数或根本没有), &exit - &main
是,我相信,根据§6.5.6/ 9未定义:
当减去两个指针时, 都应指向同一个数组对象的元素 ,或指向数组对象的最后一个元素的元素; …
添加(&main + ...)
本身是有效的, 如果添加的数量为零,可以使用,因为§6.5.6/ 7说:
对于这些运算符而言,指向不是数组元素的对象的指针的行为与以对象types作为其元素types的长度为1的数组的第一个元素的指针相同。
因此,将零加到&main
将是可以的(但没有多大用处)。
它使用recursion,指针算术,并利用整数除法的舍入行为。
所有j < 1000
, j/1000
项下降到0; 一旦j
达到1000,它评估为1。
现在,如果你有a + (b - a) * n
,其中n
是0或者1,那么最终得到a
if n == 0
,而b
如果n == 1
。 对于a
和b
,使用&main
( main()
)的地址和&exit
,当j
低于1000时, (&main + (&exit - &main) * (j/1000))
返回&main
,否则&exit
。 所得到的函数指针然后被馈送参数j+1
。
这个整个结构导致recursion行为:当j
低于1000时, main
recursion地调用它自己; 当j
达到1000时,它会调用exit
来使程序退出,退出代码为1001(这很脏但是可行)。