C99标准的 7.18.1.4 部分声明:
以下类型指定一个无符号整数类型,其属性是指向
void
的任何有效指针都可以转换为此类型,然后转换回指向 {{1 }} ,结果将与原始指针进行比较:
void
这是否意味着只有uintptr_t
类型可以转换为void *
并返回而不更改原始指针的值?
特别是,我想知道使用uintptr_t
是否需要以下代码:
uintptr_t
或者,如果C99标准保证这个更简单的版本产生相同的效果:
int foo = 42;
void * bar = &foo;
uintptr_t baz = bar;
void * qux = baz;
int quux = *(int *)qux; /* quux == foo == 42 */
在将指针转换为int foo = 42;
uintptr_t bar = &foo;
int baz = *(int *)bar; /* baz == foo == 42 */
之前是否需要转换为void *
,反之亦然?
答案 0 :(得分:6)
这种区别也存在,因为虽然任何指向对象的指针都可以转换为void *
,但C并不要求将函数指针转换为void *
又回来了!
对于指向其他类型对象的指针,C标准表示任何指针都可以转换为整数,并且整数可以转换为任何指针,但这样的结果是实现定义的。由于标准说只有void *
可以来回转换,最安全的选择是首先投射指针void *
,因为它可能是具有不同表示的指针转换为uintptr_t
时,也会产生不同的整数表示,因此可以想象:
int a;
uintptr_t up = (uintptr_t)&a;
void *p = (void *)up;
p == &a; // could be conceivably false, or it might be even that the value is indeterminate.
答案 1 :(得分:2)
有很多地方标准的作者认为没有必要强制编译器表现得合理,因为他们希望编译器无论如何都这样做。
如果某个实现定义uintptr_t
而p
是void*
,则标准对void *q = (void*)(uintptr_t)p;
所要求的唯一内容是q==p
将比较相等。标准不保证q
可用于p
可用的任何特定用途,甚至用于除与其他指针进行比较之外的任何其他目的。
从实际角度来看,没有理由要求实现应该通过void*
转换到/ uintptr_t
转换的任何一方,但标准会允许实现以任意方式运行,如果这样的额外演员被省略了。另一方面,由于标准也允许实现在几乎所有实际情况中以任意方式运行
涉及uintptr_t
,唯一真正的问题是,是否愿意依赖实施者不要以钝的方式行事。对于某些商业编译器而言,这种依赖可能是合理的,但对于一些免费的编译器则不是这样。
答案 2 :(得分:1)
是的,需要来自void *
的演员。
此段落的措辞类似于%p
格式说明符对printf
的措辞,其中void *
作为参数。
从第7.19.6.1节:
p
参数应该是指向void的指针。指针的值 转换为一系列打印字符,在 实现定义的方式。
您可以使用较少的中间变量执行上述操作:
int foo = 42;
uintptr_t baz = (void *)&foo;
int quux = *(int *)((void *)baz); /* quux == foo == 42 */
答案 3 :(得分:1)
是的,要求便携式中间转换为void*
。这是因为指向整数转换的指针是“实现定义的”,所以只要他们记录它,你的平台就可以做任何事情。
答案 4 :(得分:0)
如果我们在讨论C
中的指针,我们应该考虑如何表示它们。基本上,指针值的大小取决于体系结构而不是它所指向的类型。 void*
的值和uintptr_t
的值相同,但表示可能不同。
如果是uintptr_t
根据文档
以下类型指定带有的无符号整数类型 可以将任何有效指向void的指针转换为此类型的属性, 然后转换回指向void的指针,结果将进行比较 等于原始指针:uintptr_t。
这意味着此类型可用于安全地存储指针的值,并且由于实现特定的细节,可能等于,大于甚至小于void*
本身。
总而言之,通过转换为void*
,您可以确保转换为uintptr_t
或从.HTMLBody = .HTMLBody & "<br><B>" & ChartName & ":</B><br>" & "<img src='" &
fName(i) & "' width='800' height='400'><br>"
转换有效。