严格的指针别名:通过“易失性”访问指针/引用解决方案?

发布于 2024-09-04 08:09:50 字数 782 浏览 11 评论 0原文

紧随特定问题,一个自我回答和评论,我想了解它是否是一个正确的解决方案、解决方法/黑客或只是简单的错误。

具体来说,我重写了代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

┼── 2024-09-11 08:09:50

易失性无法帮助您避免此处的未定义行为。所以,如果它对 GCC 有效,那就很幸运了。

我们假设 T 是一个 POD。那么,执行此操作的正确方法就是

T x = …;
int i;
memcpy(&i,&x,sizeof i);
if (i==0)
  …

那里!没有严格的别名问题,也没有内存对齐问题。 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

T x = …;
int i;
memcpy(&i,&x,sizeof i);
if (i==0)
  …

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).

萌无敌 2024-09-11 08:09:50

Volatile 无法帮助您避免此处的未定义行为。

嗯,标准中关于 易失性 的任何内容都有些不清楚。我基本上同意你的回答,但现在我想稍微不同意。

为了理解 volatile 的含义,大多数人(尤其是一些编译器编写者)并不清楚该标准。最好这样想:
当使用易失性时(并且仅当使用时),C/C++ 几乎是高级汇编

当写入 易失性 左值时,编译器将发出一个 STORE,如果一个不够,则编译器将发出多个 STORE(易失性 并不意味着原子)。

当写入易失性左值时,编译器将发出一次 LOAD,如果一次不够,则发出多次 LOAD。

当然,如果没有显式的 LOAD 或 STORE,编译器只会发出暗示 LOAD 或 STORE 的指令。

sellibitze 给出了最佳解决方案:使用 memcpy 进行位重新解释。

但是,如果对内存区域的所有访问都是通过 易失性 左值完成的,很明显,严格的别名规则不适用。这就是你问题的答案。

Volatile can't help you avoid undefined behaviour here.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文