10

N3797 26.4 [complex.numbers] says this about casting std::complex<T>* to T*

4 Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:
- reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
- reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].

Does this (or some other wording of the standard) imply that I can reinterpret_cast the other way? Can I do this:

    float * pf;
    std::complex<float>* pc = reinterpret_cast<std::complex<float>*>(pf);
    pc[i].real();

As n.m. pointed out below, I would have to make sure the alignment of pf is suitable for a std::complex<float>. This can be assumed to be taken care of.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
SirGuy
  • 10,660
  • 2
  • 36
  • 66
  • Alignment requiements for `complex` may be stricter than that of `float`. – n. m. could be an AI Apr 21 '14 at 14:46
  • @n.m. Fair enough, as I understand, that can be fixed by `std::align` as per [this question](http://stackoverflow.com/questions/6973995/dynamic-aligned-memory-allocation-in-c11). – SirGuy Apr 21 '14 at 14:57
  • legal, yes `reinterpret_cast` basically just tells the compile to interpret a chunk of memory as whatever type. Safe... oh my no. – Mgetz May 12 '14 at 18:21

2 Answers2

5

No, that clause makes no such guarantee.

Now, in practice, the most common issue would be alignment: but even that may be rare.

The second problem would involve strict aliasing, where memory allocated as a double can be assumed by the compiler to not be modified by any operation involving pointers to other types (except char). The above places a restricition going the other way (a complex allocated pointer may not assume thay double*s do not point to its data), but not in the direction you want. Again this is relatively obscure, but a compiler could use this to reorder writes in your code.

It will, however, usually work. More often if you align it, and your compiler does not use strict aliasing assumptions: even then it is undefined behaviour by the standard, however.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Accessing members of `std::complex` only accesses the memory through a pointer to a `double`, so I don't see how strict aliasing is a problem. – SirGuy Apr 21 '14 at 16:59
  • @guygreer `std::complex` does not contain a pointer to `double` in any implementation I can imagine. Strict aliasing means that `double* b = new double[2]; *b = 3.0; `(*(complex*)(b)) = complex(2); std::cout << *b;` can change the print statement to `std::cout << 3.0;` because the strict aliasing violation. @guygreer – Yakk - Adam Nevraumont Apr 21 '14 at 20:43
  • There are some typos in the last comment -- I was supposed to cast to a complex pointer. My point is that aliasing need only work on layout compatible types: the standard nearly, but not quite, guarantees layout compatibility between complex and twice as many `double`s in an array. Note that this level of twistedness may not apply to any compiler you ever work with. – Yakk - Adam Nevraumont Apr 21 '14 at 21:47
  • It is a shame there doesn't seem to be a way to obtain a reference or pointer to the underlying data. Having a std::data compatible member function that returns a T* is useful for things such as simd operations on std::complex and std::complex. Vectorizing std::complex basically requires using reinterpret_cast at the moment. – Christopher Mauer Jun 09 '21 at 15:11
1

It doesn't work the other way round. A std::complex<float> is two consecutive float's in memory as proven by what the standard does allow you to do, but you have a pointer to a single float value and turn it into a pointer to a structure which should contain two floats. Even if you would have two floats, the standard doesn't guarantee it and it would therefore be illegal to reinterpret_cast to pointers in that direction.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180