While C 11 standard says this about reinterpreting std::complex<double>
as double
s:
For any pointer to an element of an array of
complex<T>
namedp
and any valid array indexi
,reinterpret_cast<T*>(p)[2*i]
is the real part of the complex numberp[i]
, andreinterpret_cast<T*>(p)[2*i 1]
is the imaginary part of the complex numberp[i]
The intent of this requirement is to preserve binary compatibility between the C library complex number types and the C language complex number types (and arrays thereof), which have an identical object representation requirement.
Is it true for the backward reinterpreting? I mean is it safe to perform something like this: std::complex<double> *cppComplexArray = reinterpret_cast<std::complex<double> *>(cDoublesArray)
where cDoublesArray
have a type of double *
and even length 2 * n
? What are potential pitfalls if its length will be odd (2 * n 1
)?
CodePudding user response:
In practice the backward reinterpreting will probably work most of the time, in view of the strong constraints of the forward reinterpreting impose (see on cppreference, std::complex
, implementation notes).
However, I'm not totally sure that such backward reinterpreting would in always work in theory:
- Let's imagine an absurd and hypothetical implementation of a complex library that would maintain a list of addresses of active complex objects (e.g. for debugging purpose). This (probably static) list would be maintained by the complex constructor and destructor.
- Every complex operation in this library would verify if its operands are in the list.
- While forward reinterpreting would work (the complex objects were well constructed and its parts can be used as doubles), the backward reinterpretation would not work (e.g. despite a compatible layout, you would reinterpret as complex a pair of doubles and if you'd perform any complex operation on them, it would fail since the complex was not properly constructed, i.e. its address is not in the list).
As said, this complex library would probably be a stupid idea. But such a library could be implemented and compliant with the standard specs. This is sufficient to prove that there is no reverse guarantee in theory.
The last point of your question is easier and more obvious to answer, supposing we would have an implementation where the reverse reinterpretation works. The missing last column would lead to an access of a part that is out of bounds. This would therfore lead to UB.
Additional readings: This working paper of the standard committee requests a general convertability feature that would generalize the bahavior of reinterpret_cast
on complex
for other types. It explains the complex case in section 4 and the special handling required from the compiler to make it work if complex is not itself implemented by an array.
CodePudding user response:
Is it true for the backward reinterpreting? I mean is it safe to perform something like this:
std::complex<double> *cppComplexArray = reinterpret_cast<std::complex<double> *>(cDoublesArray)
Casting/initialization itself is safe, using the result as-if pointing to an element of an array of std::complex<double>
is not.
When cDoublesArray
(or the array-to-pointer conversion applied to it, if cDoublesArray
denotes an array of double
s) points to the first element of an array of double
s, reinterpret_cast<std::complex<double>*>(cDoublesArray)
does the same (has the same value).
Using an expression of type std::complex<double>*
whose value «pointer to an object of type double
» (like reinterpret_cast<std::complex<double>*>(cDoublesArray)
or cppComplexArray
) in pointer arithmetic (e.g. cppComplexArray 0
) would violate [expr.add]/6:
For addition or subtraction, if the expressions
P
orQ
have type “pointer to cvT
”, whereT
and the array element type are not similar, the behavior is undefined.
(T
is std::complex<double>
, array element type is double
here, and they are not similar)