I wish to call fftw's in-place real-to-complex transform function, which has the following signature:
fftw_plan fftw_plan_dft_r2c_1d(
int n, // transform length
double* in, // pointer to input array
fftw_complex* out, // pointer to output array
unsigned flags // flags
);
The documentation says that I should indicate that I wish to perform an in-place transform by passing in aliasing pointers for the in
and out
parameters.
QUESTION: How can in
and out
alias without violating strict aliasing rules?
I am open to GCC-specific extensions (i.e., using union
s to do type-punning, even though the standard declares this to be undefined behavior). Even if this extension is permitted, a union cannot contain dynamically-sized arrays (which is a must in this applications - I do not know the transform length in advance). Does anyone have any ideas? Thanks in advance.
I'll challenge the premise: Don't worry about strict aliasing too much.
Make an array of double
and pass a pointer to it to in
. reinterpret_cast
the pointer to fftw_complex *
and pass it to out
.
Read the resulting double
s from this array (as pairs of real and imaginary components of complex numbers).
Yes, fftw_plan_dft_r2c_1d
will probably break strict aliasing under the hood if called this way.
But since it's in a separate translation unit, and caller doesn't violate strict aliasing, your compiler has no way to tell if strict aliasing was indeed violated.
fftw_complex
is essentially a struct fftw_complex {double re, im;};
, so everything should work just fine.
For extra safety you can add:
static_assert(sizeof(fftw_complex) == 2 * sizeof(double) && alignof(fftw_complex) <= alignof(double));
According to this link fftw_complex
is the following typedef
:
typedef double fftw_complex[2];
And by the pre-C++20 rules fftw_complex*
may alias double*
because of this ([basic.lval]p8.6):
If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
...
— an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union)
Array is an aggregate and our array contains double
s thus it is allowed to alias a double
pointer. Hence, no strict aliasing rule violation happens in the fftw_plan_dft_r2c_1d
function and you can safely use it.
Note, however, that this paragraph is removed from the C++20 standard and it is debated that it should be removed from the C standard as well. But since it is not removed yet and GCC & clang actually respect it I guess it is safe to assume that the behavior won't change with C++20 implementation. And MSVC, to my knowledge, doesn't take advantage of SAR at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With