通过reinterpret_cast的未对齐访问 我在讨论中试图通过C++来解释C++中是否允许未对齐的访问。我认为不是,但我很难找到标准中正确的部分来证实或反驳这一点。我一直在看C++11,但如果它更清楚的话,我可以选择另一个版本

通过reinterpret_cast的未对齐访问 我在讨论中试图通过C++来解释C++中是否允许未对齐的访问。我认为不是,但我很难找到标准中正确的部分来证实或反驳这一点。我一直在看C++11,但如果它更清楚的话,我可以选择另一个版本,c++,c++11,language-lawyer,C++,C++11,Language Lawyer,C11中未定义未对齐的访问。(§6.3.2.3,第7段)的相关部分: 指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针与引用的类型未正确对齐,则行为未定义 由于未对齐访问的行为是未定义的,一些编译器(至少是GCC)认为这意味着生成需要对齐数据的指令是可以的。大多数情况下,代码仍然适用于未对齐的数据,因为现在大多数x86和ARM指令都适用于未对齐的数据,但有些指令不适用。特别是,有些向量指令不这样做,这意味着随着编译器在生成优化指令方面的进步,使用较旧版本编译器的代码可能无法使用较

C11中未定义未对齐的访问。(§6.3.2.3,第7段)的相关部分:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针与引用的类型未正确对齐,则行为未定义

由于未对齐访问的行为是未定义的,一些编译器(至少是GCC)认为这意味着生成需要对齐数据的指令是可以的。大多数情况下,代码仍然适用于未对齐的数据,因为现在大多数x86和ARM指令都适用于未对齐的数据,但有些指令不适用。特别是,有些向量指令不这样做,这意味着随着编译器在生成优化指令方面的进步,使用较旧版本编译器的代码可能无法使用较新版本。当然,有些体系结构()在处理未对齐的数据时做得不好

当然,这更复杂。§5.2.10第7段规定:

对象指针可以显式转换为不同类型的对象指针。当“指针指向
T1
”类型的prvalue
v
转换为“指针指向cv
T2
”类型时,如果
T1
T2
都是标准布局类型,则结果为
static\u cast(v))
T2
的对准要求并不比
T1
的对准要求更严格,或者如果其中一种类型为
void
。将“指针指向
T1
”类型的PR值转换为“指针指向
T2
”类型(其中
T1
T2
是对象类型,其中
T2
的对齐要求不比
T1
的对齐要求更严格),然后返回到其原始类型,即可生成原始指针值。未指定任何其他此类指针转换的结果

请注意,最后一个单词是“未指定”,而不是“未定义”。§1.3.25将“未指定行为”定义为:

行为,对于格式良好的程序构造和正确的数据,这取决于实现

[注:实施无需记录发生的行为。可能的行为范围通常由本国际标准界定。-结束注]

除非我遗漏了什么,否则该标准实际上并没有描述这种情况下可能的行为范围,这似乎向我表明一个非常合理的行为是为C实现的行为(至少由GCC实现):不支持它们。这意味着编译器可以自由地假设未对齐的访问不会发生,并发出可能无法使用未对齐内存的指令,就像它对C所做的那样

然而,与我讨论这个问题的人有不同的解释。他们引用了§1.9第5段:

执行格式良好的程序的一致性实现应产生与具有相同程序和相同输入的抽象机器对应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,则本国际标准对使用该输入执行该程序的实现没有要求(甚至不包括第一个未定义操作之前的操作)

由于没有未定义的行为,他们认为C++编译器无权假定不对齐的访问不会发生。

是,在C++中,通过<代码> RealTytCaseAcess是未对齐的访问吗?规范(任何版本)中的哪个部分

编辑:所谓“访问”,我指的是实际加载和存储。差不多

void unaligned_cp(void* a, void* b) {
  *reinterpret_cast<volatile uint32_t*>(a) =
    *reinterpret_cast<volatile uint32_t*>(b);
}
void unaligned\u cp(void*a,void*b){
*重新解释演员阵容(a)=
*重新解释铸造(b);
}
内存的分配方式实际上超出了我的范围(它适用于可以从任何地方使用数据调用的库),但是
malloc
和堆栈上的数组都可能是候选对象。我不想对如何分配内存设置任何限制


< > > >编辑2 <强>:请引用答案(即C++标准、章节和段落)。

< >强>编辑< /强>。这回答了OP的原始问题,即“正在访问一个未对齐的指针安全”。此后,OP将他们的问题编辑为“取消对未对齐指针的引用是否安全”,这是一个更实际、更不有趣的问题


在这些情况下,指针值的往返转换结果未指定。在某些有限的情况下(包括对齐),将指向a的指针转换为指向B的指针,然后再转换回来,会生成原始指针,即使该位置没有B

如果未满足对齐要求,则往返过程——指向A的指针指向B的指针指向A的指针会导致指针具有未指定的值

由于存在无效的指针值,使用未指定的值取消引用指针可能会导致未定义的行为。在某种意义上,它与
*(int*)0xDEADBEEF
没有区别

然而,仅仅存储该指针并不是未定义的行为

<> P>以上的C++引用都没有讨论使用PoTaltoA作为Pototo to B。在所有的情况下,使用指向“错误类型”的指针,但非常有限的情况下是未定义的行为,句点。 这方面的一个示例涉及创建
std::aligned_storage\t
。你可以在那个地方建造你的
T
,它会快乐地生活,即使它“真的”
int some_ints[3] ={0};
int* some_ptr = (int*)(((char*)&some_ints[0])+1);