严格的指针别名:通过“易失性”访问指针/引用解决方案?
紧随特定问题,一个自我回答和评论,我想了解它是否是一个正确的解决方案、解决方法/黑客或只是简单的错误。
具体来说,我重写了代码:
T x = ...;
if (*reinterpret_cast <int*> (&x) == 0)
...
As:
T x = ...;
if (*reinterpret_cast <volatile int*> (&x) == 0)
...
并为指针添加了 volatile
限定符。
我们假设在我的情况下将 T
视为 int
是有意义的。通过易失性
引用进行访问是否可以解决指针别名问题?
作为参考,根据规范:
[注意:易失性是对实现的一个提示,以避免激进 涉及对象的优化,因为对象的值可能 通过实现无法检测到的方式进行更改。参见 1.9 详细的语义。一般来说,易失性的语义是 在 C++ 中与在 C 中相同。 — 尾注]
编辑:
上面的代码至少在 GCC 4.5 上确实解决了我的问题。
On the heels of a specific problem, a self-answer and comments to it, I'd like to understand if it is a proper solution, workaround/hack or just plain wrong.
Specifically, I rewrote code:
T x = ...;
if (*reinterpret_cast <int*> (&x) == 0)
...
As:
T x = ...;
if (*reinterpret_cast <volatile int*> (&x) == 0)
...
with a volatile
qualifier to the pointer.
Let's just assume that treating T
as int
in my situation makes sense. Does this accessing through a volatile
reference solve pointer aliasing problem?
For a reference, from specification:
[ Note: volatile is a hint to the implementation to avoid aggressive
optimization involving the object because the value of the object might
be changed by means undetectable by an implementation. See 1.9 for
detailed semantics. In general, the semantics of volatile are intended
to be the same in C++ as they are in C. — end note ]
EDIT:
The above code did solve my problem at least on GCC 4.5.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
易失性无法帮助您避免此处的未定义行为。所以,如果它对 GCC 有效,那就很幸运了。
我们假设 T 是一个 POD。那么,执行此操作的正确方法就是
那里!没有严格的别名问题,也没有内存对齐问题。 GCC 甚至将 memcpy 作为内部函数处理(在这种情况下没有插入函数调用)。
Volatile can't help you avoid undefined behaviour here. So, if it works for you with GCC it's luck.
Let's assume T is a POD. Then, the proper way to do this is
There! No strict aliasing problem and no memory alignment problem. GCC even handles memcpy as an intrinsic function (no function call is inserted in this case).
嗯,标准中关于 易失性 的任何内容都有些不清楚。我基本上同意你的回答,但现在我想稍微不同意。
为了理解 volatile 的含义,大多数人(尤其是一些编译器编写者)并不清楚该标准。最好这样想:
当使用
易失性
时(并且仅当使用时),C/C++ 几乎是高级汇编。当写入
易失性
左值时,编译器将发出一个 STORE,如果一个不够,则编译器将发出多个 STORE(易失性
并不意味着原子)。当写入
易失性
左值时,编译器将发出一次 LOAD,如果一次不够,则发出多次 LOAD。当然,如果没有显式的 LOAD 或 STORE,编译器只会发出暗示 LOAD 或 STORE 的指令。
sellibitze 给出了最佳解决方案:使用
memcpy
进行位重新解释。但是,如果对内存区域的所有访问都是通过
易失性
左值完成的,很明显,严格的别名规则不适用。这就是你问题的答案。Well, anything regarding
volatile
is somewhat unclear in the standard. I mostly agreed with your answer, but now I would like to slightly disagree.In order to understand what
volatile
means, the standard is not clear for most people, notably some compiler writers. It is better to think:when using
volatile
(and only when), C/C++ is pretty much high level assembly.When writing to a
volatile
lvalue, the compiler will issue a STORE, or multiple STORE if one is not enough (volatile
does not imply atomic).When writing to a
volatile
lvalue, the compiler will issue a LOAD, or multiple LOAD if one is not enough.Of course, where there is no explicit LOAD or STORE, the compiler will just issue instructions which imply a LOAD or STORE.
sellibitze gave the best solution: use
memcpy
for bit reinterpretations.But if all accesses to a memory region are done with
volatile
lvalues, it is perfectly clear that the strict aliasing rules do not apply. This is the answer to your question.