示例:
std::ptrdiff_t dist(void* a, void* b)
{
return static_cast<std::uint8_t*>(b) - static_cast<std::uint8_t*>(a);
}
Align8Type align8; // alignof(Align8Type) == 8
std::uintptr_t(&align8) & 3; // [1]
dist(nullptr, &align8) & 3; // [2]
Align8Type* p = reinterpret_cast<Align8Type*>(static_cast<std::uint8_t*>(nullptr) + dist(nullptr, &align8));
assert(&align8 == p); // [3]
假设支持std::uint8_t
,是[1]&amp;的结果[2]保证为0并且[3]保证在c ++标准中为真?
如果不是,那么在实践中呢?
答案 0 :(得分:4)
标准不保证指针的表示[注1]。指针的值不一定直接映射到连续的整数,也不一定指向具有不同对齐的类型的指针具有相同的表示。因此,以下任何一项可能:
段/偏移表示,其中段号占用指针表示的低位。
预对齐表示,其中从表示中删除具有已知对齐的对象的地址的低位0。
标记表示,其中指向某些对象类型的指针的低位用于标识类型的一个方面,并且不参与地址解析。 (这方面的一个例子是硬件辅助垃圾收集架构,其中指向大到足以成为指针的类型的指针的低位比特被重新用作GC标志。)
子字寻址表示,其中底层硬件是字寻址的(并且字长于8位),但是硬件或软件解决方案可用于字节寻址,其中字节指针由一对字节指针组成字地址/子字偏移量。在这种情况下,字节指针将大于标准所允许的字指针。
我确信还有其他可能性。
对齐必须是2的幂,但不能保证存在多个对齐。所有类型完全可能具有对齐1.因此,在给定的体系结构中,很可能无法有意义地定义Align8Type
。
鉴于以上所述,我的解释是:
std::uintptr_t(&align8) & 3 == 0
假。即使Align8Type
可以定义,也不能保证Align8Type*
到std::uintptr_t
的转换为可被8整除的数字。例如,在32位字寻址机器上,底层硬件地址mod 8可以是0,2,4或6.
dist(nullptr, &align8) & 3 == 0
假。从指向对象的指针中减去nullptr
是未定义的行为。 (§5.7/ 5:“除非两个指针都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,否则行为是未定义的。”)
reinterpret_cast<Align8Type*>(static_cast<std::uint8_t*>(nullptr) + dist(nullptr, &align8)) == &align8
假。首先,根据2.,dist
的调用是未定义的行为。其次,将该值添加到空指针是Undefined Behavior。
如果T1*
的对齐要求不如T2*
那么严格,则保证T1*
到T2
并回到T1
的往返转换( §5.2.10/ 7)。在这种情况下,T1
为Align8Type
而T2
为uint8_t
,并且对齐限制可能会成立,因此如果不是算术的未定义行为,则会工作。也就是说,您可以将&align8
投射到uint8_t*
,然后将其转发回Align8Type
。您甚至可以将整数0
添加到中间uint8_t*
指针,但不能添加其他整数。
这些身份在实践中 吗?他们可能在8位字节寻址2的补码机器上进行C ++实现,这很常见(比上面提到的理论上更常见,从统计学上讲,它们与独角兽一样常见)。但从技术上讲,它们使您的代码不可移植。我不知道积极优化可能会对第2点和第3点中提到的UB做什么,所以我不建议在生产代码中冒险。
§3.9.2/ 3:
指针类型的值表示是实现定义的。
§5.2.10/ 4:
指针可以显式转换为足以容纳它的任何整数类型。映射功能是 实现定义。 [注意:对于那些了解底层机器的寻址结构的人来说,这并不奇怪。 - 后注]
我重现了这个注释,因为它很有意思:为了理解一个地址作为整数的表示,你必须理解底层机器的寻址结构(暗示,它可能不像连续的序列那样简单。整数)。
答案 1 :(得分:0)
在C ++标准中,
声明为字符(char)的对象应足够大以存储 实现的基本字符集的任何成员。
C ++内存模型中的基本存储单元是字节。一个 byte至少足以包含basic的任何成员 执行字符集(2.3)和8位代码单元 Unicode UTF-8编码形式,由一个连续的序列组成 位数,其数量是实现定义的。
每个字节都有一个唯一的地址。
uint_8
不一定是字节。并且一个字节不一定是8位
是[1]&amp;的结果[2]保证为0?
假设Align8Type具有8字节对齐的地址:
[1]是:根据先前假设的定义。
[2]是的,即使字节大小可能大于uint_8,假设Align8Type有一个8字节对齐的地址,地址将是8的倍数。(uint_8小于或等于一个字节)
c ++标准中[3]是否保证为真?
否:dist
返回两个指针之间的uint_8
距离,而不是地址距离。
编辑:
编辑以回答重新定义的问题。