将非`void`指针转换为`uintptr_t`,反之亦然

有两个相关的C标准规则:

C99标准, 6.3.2.3

指向void的指针可以转换为指向任何不完整或对象类型的指针。 指向任何不完整或对象类型的指针可能会转换为指向void的指针并再次返回; 结果应该等于原始指针。

并且7.20.1.4

下面的类型指定一个无符号整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将与原始指针进行比较: uintptr_t

这意味着,以下代码符合:

 int *p = NULL; void *q = (void*)p; uintptr_t s = (uintptr_t)q; 

但它真的需要两步演员吗? 如果执行以下操作,编译器是否会执行隐式中间转换:

 int *p = NULL; uintptr_t s = (uintptr_t)p; 

(好吧,它可能会出现在大多数编译器上,但我的问题是标准符合性)

我不会冒险。 该标准清楚地表明了允许的内容和不允许的内容。

uintptr_t s = (uintptr_t)(void*)p; 向你的代码的读者发出信号,告诉你你正在做什么。

任何高质量的通用实现都将处理uintptr_t和非void类型之间的uintptr_t ,就好像它们是通过void*转换的一样。 标准将这种情况下的行为以及涉及指针的许多其他行为视为实施质量问题,并期望那些寻求编写高质量实现的人能够识别出有一种明显,明智和有用的方式的情况。对于程序在没有标准必须明确枚举它们的情况下的行为。 他们还认识到,有可能产生一种符合但质量很差的实施方案,以至于无用。

虽然有可能实现uintptr_t和任何非void指针类型之间的uintptr_t以实现者选择的任意方式运行,但任何人都会产生这样的转换不能以典型的方式工作并且失败的实现为了记录这种差异的充分理由,应该被认为是一个试图用劣质实施来破坏语言的破坏者。 程序员应该没有义务安抚这种行为; 除非或直到它被看作是什么,它将变得越来越糟,直到语言变得完全无用。