Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 内存地址的数字表示和对齐之间的关系?_C++_Pointers_Memory_Memory Alignment - Fatal编程技术网

C++ 内存地址的数字表示和对齐之间的关系?

C++ 内存地址的数字表示和对齐之间的关系?,c++,pointers,memory,memory-alignment,C++,Pointers,Memory,Memory Alignment,例如: 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)

例如:

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::ptrdiff\t dist(void*a,void*b)
{
返回静态强制转换(b)-静态强制转换(a);
}
align8键入align8;//alignof(Align8Type)==8
std::uintpttr_t(&align8)&3;//[1]
距离(nullptr,&align8)&3;//[2]
Align8Type*p=重新解释强制转换(静态强制转换(nullptr)+距离(nullptr和align8));
断言(&align8==p);//[3]

<强> >代码> STD::UIT88T T <代码>支持< /强>,结果是[1 ]和[2 ]保证为0,并且(3)保证在C++标准中是真的吗? 如果不是,那么在实践中呢?

< P>在C++标准中,

声明为字符(char)的对象应足够大,以便存储 实现的基本字符集的任何成员

< > C++内存模型中的基本存储单元是字节。A. 字节至少足够大,可以包含基本 执行字符集(2.3)和 Unicode UTF-8编码形式,由连续序列组成 位数,位数由实现定义

每个字节都有一个唯一的地址

一个
uint_8
不一定是一个字节。一个字节不一定是8位

是否保证[1]和[2]的结果为0?

假设Align8Type的地址为8字节对齐:

[1] 是:根据前面假设的定义

[2] 是的,即使字节大小可能大于uint_8,假设Align8Type有一个地址8字节对齐,地址也将是8的倍数。(uint_8小于或等于一个字节)

<>强> >(3)在C++标准中是否成立?< /强> < /P> 否:
dist
返回两个指针之间的
uint_8
距离,而不是地址距离

编辑:


编辑以回答重新定义的问题。

本标准不保证指针的表示形式[注1]。指针的值不一定直接映射到连续整数,指向不同对齐类型的指针也不一定具有相同的表示形式。因此,以下任何一项都是可能的:

  • 段/偏移表示法,其中段编号占据指针表示法的低位

  • 预对齐表示法,其中从表示法中删除具有已知对齐方式的对象地址的低位0

  • 标记表示法,其中指向特定对象类型的指针的低位用于标识类型的一个方面,不参与地址解析。(这方面的一个例子是硬件辅助的垃圾收集体系结构,其中指向足够大的类型的指针的低阶位被重新用作GC标志。)

  • 子字寻址表示法,其中底层硬件是字寻址的(一个字比8位长得多),但一个硬件或软件解决方案可用于字节寻址,其中一个字节指针由一对字地址/子字偏移组成。在这种情况下,字节指针将大于单词指针,这是标准允许的

  • 我相信还有其他的可能性

    对齐必须是2的幂,但不能保证存在多个对齐。所有类型都完全可能有对齐1。因此,很可能是在给定的体系结构上,不可能有意义地定义
    Align8Type

    鉴于上述情况,我的解释是:

  • std::uintptr\u t(&align8)&3==0

    错。即使
    Align8Type
    是可定义的,也不能保证
    Align8Type*
    std::uintptr\u t
    的转换是可被8整除的数字。例如,在32位字寻址机器上,底层硬件地址mod 8可以是0、2、4或6

  • dist(nullptr和align8)&3==0

    错。从指向对象的指针中减去
    nullptr
    是未定义的行为。(§5.7/5:“除非两个指针都指向同一数组对象的元素,或者一个指针超过数组对象的最后一个元素,否则行为是未定义的。”)

  • 重新解释强制转换(静态强制转换(nullptr)+dist(nullptr和align8))==&align8

    错。首先,根据2,
    dist
    的调用是未定义的行为。其次,将该值添加到空指针是未定义的行为

    只要
    T2
    的校准要求低于
    T1
    (§5.2.10/7),就可以保证
    T1*
    T2*
    再回到
    T1*
    的往返转换。在这种情况下,
    T1
    Align8Type
    T2
    uint8\u t
    ,并且对齐限制可能成立,因此如果不是因为算术的未定义行为,这将起作用。也就是说,您可以将
    &align8
    强制转换为
    uint8*
    ,然后将其强制转换回
    Align8Type
    。您甚至可以将整数
    0
    添加到中间
    uint8\u t*
    指针,但不能添加其他整数


  • 这些身份在实践中有效吗?他们可能在C++实现上工作在8位字节寻址的2补码机上,这是非常常见的(比上面提到的理论动物更常见,在统计学上,与独角兽一样常见)。但从技术上讲,它们使您的代码不可移植。我不知道积极的优化会对第2点和第3点中提到的UB做什么,所以我不建议在生产代码中冒险


    笔记:
  • §3.9.2/3:

    指针类型的值表示由实现定义

    §5.2.10/4:

    指针可以显式转换为任何足以容纳它的整数类型。m