在将指针转换为`uintptr_t`之前是否需要转换为`void *`,反之亦然?

时间:2017-07-27 13:27:32

标签: c casting language-lawyer c99 void-pointers

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 *,反之亦然?

5 个答案:

答案 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_tpvoid*,则标准对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>" 转换有效。