我现在用 c99 工作了几个星期,专注于未定义的行为。我想在遵守规则的同时测试一些奇怪的代码。结果是这段代码:
(请原谅我的变量名,我吃了一个小丑)
int main(int arg, char** argv)
{
unsigned int uiDiffOfVars;
int LegalPointerCast1, LegalPointerCast2, signedIntToRespectTheRules;
char StartVar;//Only use to have an adress from where we can move on
char *TheAccesingPointer;
int iTargetOfPointeracces;
iTargetOfPointeracces= 0x55555555;
TheAccesingPointer = (char *) &StartVar;
LegalPointerCast2 = (int) &StartVar;
LegalPointerCast1 = (int) &iTargetOfPointeracces;
if ((0x80000000 & LegalPointerCast2) != (0x80000000 & LegalPointerCast1))
{
//as im not sure in how far
//"— Apointer is converted to other than an integer or pointer type (6.5.4)." is treating unsigned integers,
//im checking this way.
printf ("try it on next machine!\r\n");
return 1;
}
if ((abs (LegalPointerCast1) > abs (LegalPointerCast2)))
uiDiffOfVars = abs (LegalPointerCast1) - abs (LegalPointerCast2);
else
uiDiffOfVars = abs (LegalPointerCast2) - abs (LegalPointerCast1);
LegalPointerCast2 = (int) TheAccesingPointer;
signedIntToRespectTheRules = abs ((int) uiDiffOfVars);
if ((abs (LegalPointerCast1) > abs (LegalPointerCast2)))
TheAccesingPointer = (char *)(LegalPointerCast2 + signedIntToRespectTheRules);
else
TheAccesingPointer = (char *)(LegalPointerCast2 - signedIntToRespectTheRules);
printf ("%c\r\n", *TheAccesingPointer);//Will the output be an 'U' ?
return 0;
}
所以这段代码是最好的未定义行为。我得到不同的结果,无论我没有访问任何我不拥有的内存区域,也没有访问任何未初始化的内存。(AFAIK)
第一个关键规则是,我不允许添加或减去指针,这会让它们离开数组边界。但是我可以将指针转换为整数,我可以根据需要进行计算,不是吗?
我的第二个假设是因为我被允许为指针分配一个有效的地址,将这个计算的地址分配给一个指针是一个有效的操作。由于我使用的是 char 指针,因此也不会违反严格的别名规则,因为 char* 可以对任何东西进行别名。
那么哪条规则被打破了,这会导致 UB?
单个变量也可以理解为“数组”,我违反了这个规则吗?
— 指向或超出数组对象和整数类型的指针的加法或减法会产生不指向或仅超出同一数组对象的结果(6.5.6)。
如果是这样,我也可以这样做吗?
int var;
int *ptr;
ptr = &var;
ptr = ptr + 1;
因为结果几乎可以肯定是未定义的行为。使用 MSVC2010 编译它会输出预期的“U”,但在使用 clang 和 gcc 的 freeBSD 上,我每次都会根据优化级别得到非常有趣和不同的结果。(在我看来,行为定义不应该如此)。
那么有什么想法是导致这种鼻龙的原因吗?