首先,请允许我强调这个问题本质上是 legalistic 。我不询问以下程序是否会在实际中对实际实现起作用,我根据对ISO的最严格的法律解释来询问它是否合法(:=不产生未定义的行为) -9899标准(:1999和:2011)。
问题是是否允许将指针转换为uintptr_t
整数,对该整数执行某些算术运算,将其返回到相同的值,并将整数转换回指针。
那么,以下程序是否合法(从某种意义上说它不会产生未定义的行为)?
#include <stdint.h>
#include <stdio.h>
int
main(void)
{
int answer = 42; void *ptr;
uintptr_t deepthought;
ptr = &answer;
deepthought = (uintptr_t)ptr;
ptr = 0;
deepthought ^= 0xdeadbeef;
printf("I'm thinking about it...\n");
deepthought ^= 0xdeadbeef;
ptr = (void *)deepthought;
printf("The answer is: %d\n", *((int *)ptr));
return 0;
}
同样,我知道这段代码对任何真实系统都没有任何困难。问题是它是否符合C标准中的法律术语,尤其是。 ISO-9899:1999 /§7.20.1.4中ISO-9899:2011中的§7.18.1.4,其中短语“具有任何有效指向void
的属性的无符号整数类型可以转换为此类型,然后转换回指向void
的指针,结果将等于原始指针“:不清楚是否”然后转换回“允许中间算术计算。
为了使问题不那么理论化,这就是为什么人们可能希望禁止这种处理的原因。如果我们稍微改变一下这个例子,那么指针就是malloc
而不是指向一个局部变量,如果它碰巧在带有(保守的)垃圾收集器的实现上运行,那么可以想象内存在printf
电话会议期间回收,因为在那一刻,没有任何东西指向那个记忆区域。因此,如果C标准使上述示例非法(例如,如果没有任何东西可以写入一直没有合法指针值的指针),这就为垃圾收集器做出的假设提供了法律依据。
但我重申,问题在于C标准的解释学,而不是任何实际或现实的结果。
答案 0 :(得分:1)
是的,它必须有效。
从我阅读Standardese的方式来看,你可以将deepthought
的值写入文件(比如fwrite
),销毁程序中值的任何副本,然后从中读取值再次归档(fread
)。读取并转换为指针的值必须与原始指针相等。我没有找到任何禁止这样做的措辞。
可以移动对象地址的垃圾收集器必须考虑这些可能性。