以下代码使用gcc输出14。为什么?
printf("%d", (int*)2+3); // This code is meant to be obfuscated!
答案 0 :(得分:11)
int *
将2
作为地址投射。添加3
会向其添加3*sizeof(int)
。在您的系统上,似乎sizeof(int)
等于4
,这就是它给2 + 12 = 14
的原因。
但是,您应该注意到给定的代码调用未定义的行为有两个原因:
对不指向数组元素的指针执行算术会导致未定义的行为。
如果转换规范无效,则行为未定义。 282)如果任何参数是 不是相应转换规范的正确类型,行为是 未定义。
答案 1 :(得分:4)
这里有两个问题。
首先,您的表达式(int*)2+3
导致未定义的行为,因为[几乎可以肯定] 0x2
处没有有效数组扩展为0xE
(14):
[C99: 6.5.6/8]:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)分别指向数组对象的第i + n和第i-n个元素,只要它们存在即可。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数。
第二个是您使用%d
格式说明符但提供指针类型的对象:
[C99: 7.19.6.1/9]:
如果转换规范无效,则行为未定义。 如果任何参数不是相应转换规范的正确类型,则行为是 未定义。强>
这些因素中的任何一个足以说明你的程序没有任何有意义的输出。但是,如果你确实看到" 14"它是因为(int*)2
导致指向0x2
内存的指针,并且应用指针算术+3
,尽管未定义的行为可能再添加sizeof(int)*3
0x2 + 4*3
1}}到指针。 0x2 + 12
→0xE
→%d
(14)。问题是通过sizeof(int) != sizeof(int*)
打印此指针值甚至可能是{{1}}的系统上的安全漏洞。
如果你在面试中没有给出这个答案,你就不应该有这份工作;如果你在面试中没有给出这个答案,但你得到了这份工作,你就不应该接受这份工作。
答案 2 :(得分:0)
我认为它的代码无效,因为我们将整数指针(int *)传递给printf的第二个参数,并在第一个参数中定义一个整数格式(%d)。
我在c中没有更多的知识,但这是我的想法。