8

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.

Community
  • 1
  • 1

2 Answers2

17

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

sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • 1
    "Volatile can't help you avoid undefined behaviour here" — why? Do you have any source for this statement? –  Jun 05 '10 at 20:07
  • 6
    C++ standard, section 3.10 paragraph 15 is the place you need to look at with respect to strict aliasing. There's no mention of an exception involving volatile. – sellibitze Jun 05 '10 at 20:54
  • There are cases where it's not undefined behavior. For example `struct A { int a; }; int main() { X x; *reinterpret_cast(&x) = 10; }` is fine and perfectly defined according to `9.2/17`. The object is of type `int`, and the lvalue is also of type `volatile int`, thus the aliasing goes fine. – Johannes Schaub - litb Jun 06 '10 at 10:41
  • @Johannes: In my case `T` could be anything, only the size matches `int`. E.g. a pointer on many platforms will do. –  Jun 06 '10 at 13:23
  • 3
    @Johannes: I didn't mean to imply that it's always undefined behaviour. I just meant to say that volatile won't make any difference with respect to 3.10/15. – sellibitze Jun 06 '10 at 19:57
  • @sellibitze, ah that makes sense now. Somehow i missed the "Does this accessing through a volatile reference solve pointer aliasing problem?" part :) thanks – Johannes Schaub - litb Jun 06 '10 at 20:13
  • 1
    Using memcpy is not guaranteed to work if the destination has no declared type, and the type as which it will next be read doesn't match the effective type of the source. If one wants to write code "oprimization proof", it's necessary to load and store individual characters in a way that can't be construed as being an operation on a character array. – supercat Mar 23 '17 at 20:53
-7

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.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
  • 6
    -1: First, this is not a forum; we don't address other answers in answers. If you think you have a better answer, then write an answer that addresses the question. Second and more importantly, "anything regarding volatile is somewhat unclear in the standard." No, it isn't. The standard is *very* clear on how volatile and non-volatile works with regard to the abstract machine. – Nicol Bolas Jul 21 '12 at 19:29
  • 1
    @NicolBolas "_Second and more importantly, "anything regarding volatile is somewhat unclear in the standard." No, it isn't._" A lot of people think it is extremely unclear. If you think it is clear, please explain what it means, and my interpretation is correct. – curiousguy Jul 21 '12 at 19:32
  • 1
    @NicolBolas "_First, this is not a forum;_" Except it is a forum. We are discussing things. It's the definition of a forum. "_we don't address other answers in answers._" So I am supposed to discuss this in a comment, then someone will tell me I discuss too many things in comment... – curiousguy Jul 21 '12 at 19:40
  • "So I am supposed to discuss this in a comment, then someone will tell me I discuss too many things in comment." Exactly. That's how we keep discussion out of this Q&A site, thus maintaining a focus on the question. We don't generally want people to address another answer like this in answers; we want the focus to be answering the person's question. Which you admit sellibitze did. – Nicol Bolas Jul 21 '12 at 20:38
  • @NicolBolas 1) This is too large for a comment. 2) Please. Read. My. Answer. – curiousguy Jul 21 '12 at 20:52
  • @NicolBolas "_we want the focus to be answering the person's question. Which you admit sellibitze did_" actually, he did **not** answered the question of the use of `volatile` (only the specific example of the use of `volatile`). I answered the question regarding the use of `volatile`. sellibitze said: no it does not work. I said: it works, but not the way you wrote it. Anyway, this is a bad idea, and follow sellibitze's suggestion to use `memcpy`. Your attacks are not warranted. – curiousguy Jul 21 '12 at 23:48
  • 2
    The behavior of `volatile` accesses is *Implementation-Defined*, as such it may be possible for an implementation to define behavior in such a way that it would not guard against aliasing-related UB. A compiler written by sane mature individuals should have no problem writing and reading a `volatile` location using different types. Alas, some compiler writers would rather seek out excuses for treating something as Undefined Behavior than generate useful code. – supercat Aug 22 '15 at 23:48