我正在讨论试图弄清楚C++中是否允许未对齐访问reinterpret_cast.我想不是,但我找不到确认或反驳的标准的正确部分.我一直在看C++ 11,但是如果它更清楚的话,我可以使用另一个版本.
C11中未定义未对齐的访问权限.C11标准的相关部分(第6.3.2.3段,第7段):
指向对象类型的指针可以转换为指向不同对象类型的指针.如果生成的指针未针对引用的类型正确对齐,则行为未定义.
由于未定义访问的行为未定义,因此某些编译器(至少是GCC)认为可以生成需要对齐数据的指令.大多数情况下,代码仍适用于未对齐的数据,因为现在大多数x86和ARM指令都使用未对齐的数据,但有些则没有.特别是,某些向量指令不会,这意味着随着编译器在生成优化指令方面变得更好,使用旧版本编译器的代码可能无法与较新版本一起使用.当然,某些体系结构(如MIPS)与未对齐数据的效果不同.
当然,C++ 11更复杂.§5.2.10,第7段说:
可以将对象指针显式转换为不同类型的对象指针.当prvalue
v类型的"指针T1"被转换为类型"指向cvT2",结果是static_cast<cv T2*>(static_cast<cv void*>(v))如果两个T1和T2是标准布局类型(3.9)和的对准要求T2并不比那些更严格的T1,或者如果任一类型是void.将"指向T1"的类型的prvalue转换为"指向"的类型T2(其中T1和T2是对象类型,并且对齐要求T2不比那些更严格T1)并返回其原始类型,产生原始指针值.未指定任何其他此类指针转换的结果.
请注意,最后一个单词是"未指定",而不是"未定义".§1.3.25将"未指明的行为"定义为:
行为,对于格式良好的程序构造和正确的数据,取决于实现
[ 注意:不需要实现来记录发生的行为.本国际标准通常描述了可能的行为范围.- 结束说明 ]
除非我遗漏了某些内容,否则标准实际上并没有描述这种情况下可能的行为范围,这似乎向我表明,一个非常合理的行为是为C实现的行为(至少由GCC实现):不支持他们.这意味着编译器可以自由地假设未发生未对齐访问并发出可能无法使用未对齐内存的指令,就像它对C一样.
然而,我与之讨论的人有不同的解释.他们引用第1.9段第5段:
执行格式良好的程序的一致实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为.但是,如果任何此类执行包含未定义的操作,则此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作).
由于没有未定义的行为,他们认为C++编译器无权假设未发生未对齐访问.
那么,reinterpret_cast在C++中通过安全进行未对齐的访问吗?它在说明书(任何版本)中的位置如何?
编辑:通过"访问",我的意思是实际加载和存储.就像是
void unaligned_cp(void* a, void* b) {
*reinterpret_cast<volatile uint32_t*>(a) =
*reinterpret_cast<volatile uint32_t*>(b);
}
Run Code Online (Sandbox Code Playgroud)
如何分配内存实际上超出了我的范围(它适用于可以从任何地方调用数据的库),但是malloc …
TL;DR:我需要相当于 C11 的 Microsoft C(不是 C++)atomic_load。有谁知道正确的功能是什么?
我有一些使用原子的非常标准的代码。就像是
do {
bar = atomic_load(&foo);
baz = some_stuff(bar);
} while (!atomic_compare_exchange_weak(&foo, &bar, baz));
Run Code Online (Sandbox Code Playgroud)
我想弄清楚如何用 MSVC 处理它。CAS 很简单 ( InterlockedCompareExchange),但atomic_load事实证明更麻烦。
也许我遗漏了一些东西,但MSDN上的同步函数列表似乎没有任何简单加载的东西。我唯一能想到的就是这样的东西InterlockedOr(object, 0),它会为每个负载生成一个商店(更不用说围栏了)……
只要变量是可变的,我认为只读取值是安全的,但是如果我这样做,Visual Studio 的代码分析功能会发出一堆C28112警告(“通过互锁函数访问的变量 (foo) 必须始终可以通过互锁功能访问。”)。
如果简单的阅读真的是正确的方式,我想我可以用类似的东西让那些人沉默
#define atomic_load(object) \
__pragma(warning(push)) \
__pragma(warning(disable:28112)) \
(*(object)) \
__pragma(warning(pop))
Run Code Online (Sandbox Code Playgroud)
但是分析器坚持我应该始终使用这些Interlocked*函数,这让我相信一定有更好的方法。如果是这样,那是什么?
我目前正在尝试了解glibc启动例程(__libc_start_main)如何处理Elf辅助矢量类型(auxv_t).
浏览glibc的源代码,我找到了一些名为GLRO的函数的引用.在尝试追踪此函数的定义时,我能找到的最接近的是
#define GLRO(x) _##x
Run Code Online (Sandbox Code Playgroud)
当我搜索" ## x"时,我发现的是其他类似的"#define"指令,让我感到困惑.这个定义是什么意思?" ## x"是某种编译器指令吗?