Have fun with unix
突然想起小伙伴前段时间给我看的一段神仙代码。实在特有诱惑力了。。当时女票喊我吃饭我都在看这段代码,话不多说,放码过来。
1 | printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60); |
要解开这道题,我们首先要知道下面几点。
a[3]
==3[a]
转换为指针角度看,a[3] = *(a+3) = *(3+a) = 3[a]
"abcdefg"[3]
这种表示相当于char str[]="abcdefg"; str[3]
- 知道了上面那点后,我的目光就聚焦在
unix
上,我感觉它应该是一个数字,一开始以为它是个变量,但代码中没有描述,我问小伙伴这是不是全量代码,小伙伴说文章里没有看到其他的。。于是我就开始猜他的值,一开始猜的 3,是因为忘记了字符串中 “\0xx” 的意义,把他们当成了 3 个字符来看。其实它们是一个字符的,这种格式表示八进制的 ASCII 码。然后猜unix
值为 1,后面才晓得unix
是个宏定义,#define unix 1
,这样,我们可以将上面的题目转换成较易看懂的。
1 | printf( &("\021%six\012\0"[1]), "have"[1]+"fun"-0x60); |
众所周知, printf()
的第一个参数为字符串,或者说字符串的起始地址,我们分析后可知为 %six\012\0
, '%s'
表示一个字符串,故我们看第 2 个参数, have[1]
也便是 'a'
,'a'-0x60
= 97 - 96 = 1, "fun"+1
也便是字符串 "un"
的起始地址,\012
= 10, 对应 ASCII
码也便是 \n
。
所以这段代码其实是 printf("unix\n");
。
unix
很棒很惊艳的代码。
再延伸一下吧,平常打 ACM 的时候我经常会用到 printf("%d%c", ans[i], " \n"[i==n-1])
表示每个之间用空格隔开,最后一个后面换行。