Proper way to call a c-function taking non-const pointer arguments, const_cast, reinterpret_cast, launder
What is proper way to call a c-function taking non-const custom pointer arguments from c++?
Take, as a very common example, the function fftw_plan_dft_1d
from FFTW3. http://fftw.org/fftw3_doc/Complex-DFTs.html#Complex-DFTs
fftw_plan fftw_plan_dft_1d(int n0,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
(fftw_complex
is a typedef for double[2]
).
Suppose I want apply this function to a couple of const-correct c++ containers.
std::vector<std::complex<double>> const In = {...};
std::vector<std::complex<double>> Out(In.size());
How should I do that?
_ First iteration, I have to extract the data pointer from the container,
assert(In.size() == Out.size());
fftw_plan fftw_plan_dft_1d(In.size(),
In.data(), Out.data(), // error const
FFTW_FORWARD, FFTW_ESTIMATE);
_ Second iteration
but since it is const I have to constcast.
I assume that this is the only possible solution assuming that the reason for the C-interfact is that C doesn't have const arguments.
fftw_plan p = fftw_plan_dft_1d(In.size(),
const_cast<std::complex<double>*>(In.data()), // error std::complex is not convertible to fftw_complex
Out.data(),
FFTW_FORWARD, FFTW_ESTIMATE);
_ Third iteration
Now, I have to convert std::complex<double>
to fftw_complex
(double[2]
). Fortunately std::complex<double>
is required to have the same layout as double[2]
.
fftw_plan p = fftw_plan_dft_1d(In.size(),
reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data())), // is this UB?
reinterpret_cast<fftw_complex*>(Out.data()),
FFTW_FORWARD, FFTW_ESTIMATE);
and now I am paranoid, apparently reinterpret_cast
is always UB.
I don't know how to use std::launder
but I know that it can save reinterpret_cast
UB in certain situations.
fftw_plan p = fftw_plan_dft_1d(In.size(),
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data()))), // needs c++17
std::launder(reinterpret_cast<fftw_complex*>(Out.data())),
FFTW_FORWARD, FFTW_ESTIMATE);
At the end of the day, is this a reasonable way to call a C-function that involves const and reinterpretation of types?
Am I too paranoid? or is it just that calling C from C++ is always formally UB in cases like these and I can't do anything about it?
c c++17 reinterpret-cast const-cast
add a comment |
What is proper way to call a c-function taking non-const custom pointer arguments from c++?
Take, as a very common example, the function fftw_plan_dft_1d
from FFTW3. http://fftw.org/fftw3_doc/Complex-DFTs.html#Complex-DFTs
fftw_plan fftw_plan_dft_1d(int n0,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
(fftw_complex
is a typedef for double[2]
).
Suppose I want apply this function to a couple of const-correct c++ containers.
std::vector<std::complex<double>> const In = {...};
std::vector<std::complex<double>> Out(In.size());
How should I do that?
_ First iteration, I have to extract the data pointer from the container,
assert(In.size() == Out.size());
fftw_plan fftw_plan_dft_1d(In.size(),
In.data(), Out.data(), // error const
FFTW_FORWARD, FFTW_ESTIMATE);
_ Second iteration
but since it is const I have to constcast.
I assume that this is the only possible solution assuming that the reason for the C-interfact is that C doesn't have const arguments.
fftw_plan p = fftw_plan_dft_1d(In.size(),
const_cast<std::complex<double>*>(In.data()), // error std::complex is not convertible to fftw_complex
Out.data(),
FFTW_FORWARD, FFTW_ESTIMATE);
_ Third iteration
Now, I have to convert std::complex<double>
to fftw_complex
(double[2]
). Fortunately std::complex<double>
is required to have the same layout as double[2]
.
fftw_plan p = fftw_plan_dft_1d(In.size(),
reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data())), // is this UB?
reinterpret_cast<fftw_complex*>(Out.data()),
FFTW_FORWARD, FFTW_ESTIMATE);
and now I am paranoid, apparently reinterpret_cast
is always UB.
I don't know how to use std::launder
but I know that it can save reinterpret_cast
UB in certain situations.
fftw_plan p = fftw_plan_dft_1d(In.size(),
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data()))), // needs c++17
std::launder(reinterpret_cast<fftw_complex*>(Out.data())),
FFTW_FORWARD, FFTW_ESTIMATE);
At the end of the day, is this a reasonable way to call a C-function that involves const and reinterpretation of types?
Am I too paranoid? or is it just that calling C from C++ is always formally UB in cases like these and I can't do anything about it?
c c++17 reinterpret-cast const-cast
2
C does haveconst
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.
– TypeIA
Nov 13 '18 at 0:07
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or useconst_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameterFFTW_ESTIMATE
which promises not overwrite the data of first pointer.
– alfC
Nov 13 '18 at 0:11
add a comment |
What is proper way to call a c-function taking non-const custom pointer arguments from c++?
Take, as a very common example, the function fftw_plan_dft_1d
from FFTW3. http://fftw.org/fftw3_doc/Complex-DFTs.html#Complex-DFTs
fftw_plan fftw_plan_dft_1d(int n0,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
(fftw_complex
is a typedef for double[2]
).
Suppose I want apply this function to a couple of const-correct c++ containers.
std::vector<std::complex<double>> const In = {...};
std::vector<std::complex<double>> Out(In.size());
How should I do that?
_ First iteration, I have to extract the data pointer from the container,
assert(In.size() == Out.size());
fftw_plan fftw_plan_dft_1d(In.size(),
In.data(), Out.data(), // error const
FFTW_FORWARD, FFTW_ESTIMATE);
_ Second iteration
but since it is const I have to constcast.
I assume that this is the only possible solution assuming that the reason for the C-interfact is that C doesn't have const arguments.
fftw_plan p = fftw_plan_dft_1d(In.size(),
const_cast<std::complex<double>*>(In.data()), // error std::complex is not convertible to fftw_complex
Out.data(),
FFTW_FORWARD, FFTW_ESTIMATE);
_ Third iteration
Now, I have to convert std::complex<double>
to fftw_complex
(double[2]
). Fortunately std::complex<double>
is required to have the same layout as double[2]
.
fftw_plan p = fftw_plan_dft_1d(In.size(),
reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data())), // is this UB?
reinterpret_cast<fftw_complex*>(Out.data()),
FFTW_FORWARD, FFTW_ESTIMATE);
and now I am paranoid, apparently reinterpret_cast
is always UB.
I don't know how to use std::launder
but I know that it can save reinterpret_cast
UB in certain situations.
fftw_plan p = fftw_plan_dft_1d(In.size(),
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data()))), // needs c++17
std::launder(reinterpret_cast<fftw_complex*>(Out.data())),
FFTW_FORWARD, FFTW_ESTIMATE);
At the end of the day, is this a reasonable way to call a C-function that involves const and reinterpretation of types?
Am I too paranoid? or is it just that calling C from C++ is always formally UB in cases like these and I can't do anything about it?
c c++17 reinterpret-cast const-cast
What is proper way to call a c-function taking non-const custom pointer arguments from c++?
Take, as a very common example, the function fftw_plan_dft_1d
from FFTW3. http://fftw.org/fftw3_doc/Complex-DFTs.html#Complex-DFTs
fftw_plan fftw_plan_dft_1d(int n0,
fftw_complex *in, fftw_complex *out,
int sign, unsigned flags);
(fftw_complex
is a typedef for double[2]
).
Suppose I want apply this function to a couple of const-correct c++ containers.
std::vector<std::complex<double>> const In = {...};
std::vector<std::complex<double>> Out(In.size());
How should I do that?
_ First iteration, I have to extract the data pointer from the container,
assert(In.size() == Out.size());
fftw_plan fftw_plan_dft_1d(In.size(),
In.data(), Out.data(), // error const
FFTW_FORWARD, FFTW_ESTIMATE);
_ Second iteration
but since it is const I have to constcast.
I assume that this is the only possible solution assuming that the reason for the C-interfact is that C doesn't have const arguments.
fftw_plan p = fftw_plan_dft_1d(In.size(),
const_cast<std::complex<double>*>(In.data()), // error std::complex is not convertible to fftw_complex
Out.data(),
FFTW_FORWARD, FFTW_ESTIMATE);
_ Third iteration
Now, I have to convert std::complex<double>
to fftw_complex
(double[2]
). Fortunately std::complex<double>
is required to have the same layout as double[2]
.
fftw_plan p = fftw_plan_dft_1d(In.size(),
reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data())), // is this UB?
reinterpret_cast<fftw_complex*>(Out.data()),
FFTW_FORWARD, FFTW_ESTIMATE);
and now I am paranoid, apparently reinterpret_cast
is always UB.
I don't know how to use std::launder
but I know that it can save reinterpret_cast
UB in certain situations.
fftw_plan p = fftw_plan_dft_1d(In.size(),
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(In.data()))), // needs c++17
std::launder(reinterpret_cast<fftw_complex*>(Out.data())),
FFTW_FORWARD, FFTW_ESTIMATE);
At the end of the day, is this a reasonable way to call a C-function that involves const and reinterpretation of types?
Am I too paranoid? or is it just that calling C from C++ is always formally UB in cases like these and I can't do anything about it?
c c++17 reinterpret-cast const-cast
c c++17 reinterpret-cast const-cast
edited Nov 13 '18 at 0:12
asked Nov 13 '18 at 0:05
alfC
4,94722858
4,94722858
2
C does haveconst
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.
– TypeIA
Nov 13 '18 at 0:07
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or useconst_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameterFFTW_ESTIMATE
which promises not overwrite the data of first pointer.
– alfC
Nov 13 '18 at 0:11
add a comment |
2
C does haveconst
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.
– TypeIA
Nov 13 '18 at 0:07
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or useconst_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameterFFTW_ESTIMATE
which promises not overwrite the data of first pointer.
– alfC
Nov 13 '18 at 0:11
2
2
C does have
const
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.– TypeIA
Nov 13 '18 at 0:07
C does have
const
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.– TypeIA
Nov 13 '18 at 0:07
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or use
const_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameter FFTW_ESTIMATE
which promises not overwrite the data of first pointer.– alfC
Nov 13 '18 at 0:11
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or use
const_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameter FFTW_ESTIMATE
which promises not overwrite the data of first pointer.– alfC
Nov 13 '18 at 0:11
add a comment |
1 Answer
1
active
oldest
votes
I think you're indeed being quite paranoid, and I also think that's a good thing. Keep it up. A little paranoia will greatly reduce the number of times you shoot yourself in the foot!
You correctly identified the need to cast away the const
qualifier because the library doesn't use const
in its function signature. And you correctly identified the solution using const_cast<>
.
You also correctly identified that reinterpret_cast<>
is technically UB in this situation if you don't assume that fftw_complex
is typedefed as double[2]
. (I'm not familiar with FFTW3, so I don't know if that is even true or not, but you probably do.) If you know it's a typedef, it is not UB because the types are the same, just aliased under different names. If you don't know, it's "probably" still safe, but yes, I think that might be a case where you have to make a little leap of faith, knowing that any sane, real world compiler should do the right thing. There's a note to this effect in the FFTW3 documentation.
C++ has its own complex template class, defined in the standard header file. Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex *x, you can pass it directly to FFTW via reinterpret_cast(x).
(Of course this layout guarantee is now part of the standard as of C++11.)
Finally, a note about C++ style casts. Everyone says you should use them instead of C casts, and this is true in most situations, but C-style casts are well-defined and the program isn't going to blow up if you use them. The tradeoff is one of conciseness and readable code (C-style) against explicit declaration of intent (C++-style). The exact rules for what the C++ compiler does with C-style casts are defined here. In my personal opinion, since you're already dealing with a C library with less-than-perfect function signatures, it is not the end of the world to simply C-style cast to a (double *)
and call it a day.
fftw_complex
is a typedef ofdouble[2]
the problem is that I am reinterpreting fromstd::complex<double>&
todouble[2]&
.std::complex
is indeed now mandated to havedouble[2]
layout, what I don't know if that savesreinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.
– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia ofstd::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by(fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to(double*)
involved I think.)
– alfC
Nov 13 '18 at 1:29
It meansreinterpret_cast
isn't needed at all, because givenp = &c[0]
,p
andp + 1
are guaranteed to be addresses of validdouble
s and that's all you need (minus casting away theconst
). I agree thatstd::launder()
seems like overkill and personally I would probably writeconst_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.
– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees ofstd::vector
come into play here too, such that givenstd::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.
– TypeIA
Nov 13 '18 at 1:44
Thanks, you say thatreinterpret_cast
is not needed at all, but how would you callfftw_plan_dft_1d
onstd::vector<std::complex<double>>
without usingreinterpret_cast
or c-style cast? I don't see how.
– alfC
Nov 13 '18 at 3:41
|
show 2 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271883%2fproper-way-to-call-a-c-function-taking-non-const-pointer-arguments-const-cast%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think you're indeed being quite paranoid, and I also think that's a good thing. Keep it up. A little paranoia will greatly reduce the number of times you shoot yourself in the foot!
You correctly identified the need to cast away the const
qualifier because the library doesn't use const
in its function signature. And you correctly identified the solution using const_cast<>
.
You also correctly identified that reinterpret_cast<>
is technically UB in this situation if you don't assume that fftw_complex
is typedefed as double[2]
. (I'm not familiar with FFTW3, so I don't know if that is even true or not, but you probably do.) If you know it's a typedef, it is not UB because the types are the same, just aliased under different names. If you don't know, it's "probably" still safe, but yes, I think that might be a case where you have to make a little leap of faith, knowing that any sane, real world compiler should do the right thing. There's a note to this effect in the FFTW3 documentation.
C++ has its own complex template class, defined in the standard header file. Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex *x, you can pass it directly to FFTW via reinterpret_cast(x).
(Of course this layout guarantee is now part of the standard as of C++11.)
Finally, a note about C++ style casts. Everyone says you should use them instead of C casts, and this is true in most situations, but C-style casts are well-defined and the program isn't going to blow up if you use them. The tradeoff is one of conciseness and readable code (C-style) against explicit declaration of intent (C++-style). The exact rules for what the C++ compiler does with C-style casts are defined here. In my personal opinion, since you're already dealing with a C library with less-than-perfect function signatures, it is not the end of the world to simply C-style cast to a (double *)
and call it a day.
fftw_complex
is a typedef ofdouble[2]
the problem is that I am reinterpreting fromstd::complex<double>&
todouble[2]&
.std::complex
is indeed now mandated to havedouble[2]
layout, what I don't know if that savesreinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.
– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia ofstd::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by(fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to(double*)
involved I think.)
– alfC
Nov 13 '18 at 1:29
It meansreinterpret_cast
isn't needed at all, because givenp = &c[0]
,p
andp + 1
are guaranteed to be addresses of validdouble
s and that's all you need (minus casting away theconst
). I agree thatstd::launder()
seems like overkill and personally I would probably writeconst_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.
– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees ofstd::vector
come into play here too, such that givenstd::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.
– TypeIA
Nov 13 '18 at 1:44
Thanks, you say thatreinterpret_cast
is not needed at all, but how would you callfftw_plan_dft_1d
onstd::vector<std::complex<double>>
without usingreinterpret_cast
or c-style cast? I don't see how.
– alfC
Nov 13 '18 at 3:41
|
show 2 more comments
I think you're indeed being quite paranoid, and I also think that's a good thing. Keep it up. A little paranoia will greatly reduce the number of times you shoot yourself in the foot!
You correctly identified the need to cast away the const
qualifier because the library doesn't use const
in its function signature. And you correctly identified the solution using const_cast<>
.
You also correctly identified that reinterpret_cast<>
is technically UB in this situation if you don't assume that fftw_complex
is typedefed as double[2]
. (I'm not familiar with FFTW3, so I don't know if that is even true or not, but you probably do.) If you know it's a typedef, it is not UB because the types are the same, just aliased under different names. If you don't know, it's "probably" still safe, but yes, I think that might be a case where you have to make a little leap of faith, knowing that any sane, real world compiler should do the right thing. There's a note to this effect in the FFTW3 documentation.
C++ has its own complex template class, defined in the standard header file. Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex *x, you can pass it directly to FFTW via reinterpret_cast(x).
(Of course this layout guarantee is now part of the standard as of C++11.)
Finally, a note about C++ style casts. Everyone says you should use them instead of C casts, and this is true in most situations, but C-style casts are well-defined and the program isn't going to blow up if you use them. The tradeoff is one of conciseness and readable code (C-style) against explicit declaration of intent (C++-style). The exact rules for what the C++ compiler does with C-style casts are defined here. In my personal opinion, since you're already dealing with a C library with less-than-perfect function signatures, it is not the end of the world to simply C-style cast to a (double *)
and call it a day.
fftw_complex
is a typedef ofdouble[2]
the problem is that I am reinterpreting fromstd::complex<double>&
todouble[2]&
.std::complex
is indeed now mandated to havedouble[2]
layout, what I don't know if that savesreinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.
– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia ofstd::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by(fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to(double*)
involved I think.)
– alfC
Nov 13 '18 at 1:29
It meansreinterpret_cast
isn't needed at all, because givenp = &c[0]
,p
andp + 1
are guaranteed to be addresses of validdouble
s and that's all you need (minus casting away theconst
). I agree thatstd::launder()
seems like overkill and personally I would probably writeconst_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.
– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees ofstd::vector
come into play here too, such that givenstd::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.
– TypeIA
Nov 13 '18 at 1:44
Thanks, you say thatreinterpret_cast
is not needed at all, but how would you callfftw_plan_dft_1d
onstd::vector<std::complex<double>>
without usingreinterpret_cast
or c-style cast? I don't see how.
– alfC
Nov 13 '18 at 3:41
|
show 2 more comments
I think you're indeed being quite paranoid, and I also think that's a good thing. Keep it up. A little paranoia will greatly reduce the number of times you shoot yourself in the foot!
You correctly identified the need to cast away the const
qualifier because the library doesn't use const
in its function signature. And you correctly identified the solution using const_cast<>
.
You also correctly identified that reinterpret_cast<>
is technically UB in this situation if you don't assume that fftw_complex
is typedefed as double[2]
. (I'm not familiar with FFTW3, so I don't know if that is even true or not, but you probably do.) If you know it's a typedef, it is not UB because the types are the same, just aliased under different names. If you don't know, it's "probably" still safe, but yes, I think that might be a case where you have to make a little leap of faith, knowing that any sane, real world compiler should do the right thing. There's a note to this effect in the FFTW3 documentation.
C++ has its own complex template class, defined in the standard header file. Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex *x, you can pass it directly to FFTW via reinterpret_cast(x).
(Of course this layout guarantee is now part of the standard as of C++11.)
Finally, a note about C++ style casts. Everyone says you should use them instead of C casts, and this is true in most situations, but C-style casts are well-defined and the program isn't going to blow up if you use them. The tradeoff is one of conciseness and readable code (C-style) against explicit declaration of intent (C++-style). The exact rules for what the C++ compiler does with C-style casts are defined here. In my personal opinion, since you're already dealing with a C library with less-than-perfect function signatures, it is not the end of the world to simply C-style cast to a (double *)
and call it a day.
I think you're indeed being quite paranoid, and I also think that's a good thing. Keep it up. A little paranoia will greatly reduce the number of times you shoot yourself in the foot!
You correctly identified the need to cast away the const
qualifier because the library doesn't use const
in its function signature. And you correctly identified the solution using const_cast<>
.
You also correctly identified that reinterpret_cast<>
is technically UB in this situation if you don't assume that fftw_complex
is typedefed as double[2]
. (I'm not familiar with FFTW3, so I don't know if that is even true or not, but you probably do.) If you know it's a typedef, it is not UB because the types are the same, just aliased under different names. If you don't know, it's "probably" still safe, but yes, I think that might be a case where you have to make a little leap of faith, knowing that any sane, real world compiler should do the right thing. There's a note to this effect in the FFTW3 documentation.
C++ has its own complex template class, defined in the standard header file. Reportedly, the C++ standards committee has recently agreed to mandate that the storage format used for this type be binary-compatible with the C99 type, i.e. an array T[2] with consecutive real [0] and imaginary [1] parts. (See report http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2002/n1388.pdf WG21/N1388.) Although not part of the official standard as of this writing, the proposal stated that: “This solution has been tested with all current major implementations of the standard library and shown to be working.” To the extent that this is true, if you have a variable complex *x, you can pass it directly to FFTW via reinterpret_cast(x).
(Of course this layout guarantee is now part of the standard as of C++11.)
Finally, a note about C++ style casts. Everyone says you should use them instead of C casts, and this is true in most situations, but C-style casts are well-defined and the program isn't going to blow up if you use them. The tradeoff is one of conciseness and readable code (C-style) against explicit declaration of intent (C++-style). The exact rules for what the C++ compiler does with C-style casts are defined here. In my personal opinion, since you're already dealing with a C library with less-than-perfect function signatures, it is not the end of the world to simply C-style cast to a (double *)
and call it a day.
edited Nov 13 '18 at 1:47
answered Nov 13 '18 at 0:25
TypeIA
13.7k2241
13.7k2241
fftw_complex
is a typedef ofdouble[2]
the problem is that I am reinterpreting fromstd::complex<double>&
todouble[2]&
.std::complex
is indeed now mandated to havedouble[2]
layout, what I don't know if that savesreinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.
– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia ofstd::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by(fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to(double*)
involved I think.)
– alfC
Nov 13 '18 at 1:29
It meansreinterpret_cast
isn't needed at all, because givenp = &c[0]
,p
andp + 1
are guaranteed to be addresses of validdouble
s and that's all you need (minus casting away theconst
). I agree thatstd::launder()
seems like overkill and personally I would probably writeconst_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.
– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees ofstd::vector
come into play here too, such that givenstd::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.
– TypeIA
Nov 13 '18 at 1:44
Thanks, you say thatreinterpret_cast
is not needed at all, but how would you callfftw_plan_dft_1d
onstd::vector<std::complex<double>>
without usingreinterpret_cast
or c-style cast? I don't see how.
– alfC
Nov 13 '18 at 3:41
|
show 2 more comments
fftw_complex
is a typedef ofdouble[2]
the problem is that I am reinterpreting fromstd::complex<double>&
todouble[2]&
.std::complex
is indeed now mandated to havedouble[2]
layout, what I don't know if that savesreinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.
– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia ofstd::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by(fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to(double*)
involved I think.)
– alfC
Nov 13 '18 at 1:29
It meansreinterpret_cast
isn't needed at all, because givenp = &c[0]
,p
andp + 1
are guaranteed to be addresses of validdouble
s and that's all you need (minus casting away theconst
). I agree thatstd::launder()
seems like overkill and personally I would probably writeconst_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.
– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees ofstd::vector
come into play here too, such that givenstd::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.
– TypeIA
Nov 13 '18 at 1:44
Thanks, you say thatreinterpret_cast
is not needed at all, but how would you callfftw_plan_dft_1d
onstd::vector<std::complex<double>>
without usingreinterpret_cast
or c-style cast? I don't see how.
– alfC
Nov 13 '18 at 3:41
fftw_complex
is a typedef of double[2]
the problem is that I am reinterpreting from std::complex<double>&
to double[2]&
. std::complex
is indeed now mandated to have double[2]
layout, what I don't know if that saves reinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.– alfC
Nov 13 '18 at 1:25
fftw_complex
is a typedef of double[2]
the problem is that I am reinterpreting from std::complex<double>&
to double[2]&
. std::complex
is indeed now mandated to have double[2]
layout, what I don't know if that saves reinterpret_cast
from being UB, cppreference seems to say that reinterpret is ok here (at least for refences, doesn't say anything about pointers) en.cppreference.com/w/cpp/numeric/complex.– alfC
Nov 13 '18 at 1:25
I am tempted from you answer to say that all the paranoia of
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by (fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to (double*)
involved I think.)– alfC
Nov 13 '18 at 1:29
I am tempted from you answer to say that all the paranoia of
std::launder(reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(in)))
can be simply replaced by (fftw_complex*)in
, because I am using C-library anyway. Good. (BTW there is no cast to (double*)
involved I think.)– alfC
Nov 13 '18 at 1:29
It means
reinterpret_cast
isn't needed at all, because given p = &c[0]
, p
and p + 1
are guaranteed to be addresses of valid double
s and that's all you need (minus casting away the const
). I agree that std::launder()
seems like overkill and personally I would probably write const_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.– TypeIA
Nov 13 '18 at 1:43
It means
reinterpret_cast
isn't needed at all, because given p = &c[0]
, p
and p + 1
are guaranteed to be addresses of valid double
s and that's all you need (minus casting away the const
). I agree that std::launder()
seems like overkill and personally I would probably write const_cast<double *>(&c[0][0])
but I see nothing wrong with the C-style cast version.– TypeIA
Nov 13 '18 at 1:43
Also maybe worth observing that the layout guarantees of
std::vector
come into play here too, such that given std::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.– TypeIA
Nov 13 '18 at 1:44
Also maybe worth observing that the layout guarantees of
std::vector
come into play here too, such that given std::vector<std::complex> v
, you can safely assume that the double components of each complex value are all packed at consecutive memory addresses.– TypeIA
Nov 13 '18 at 1:44
Thanks, you say that
reinterpret_cast
is not needed at all, but how would you call fftw_plan_dft_1d
on std::vector<std::complex<double>>
without using reinterpret_cast
or c-style cast? I don't see how.– alfC
Nov 13 '18 at 3:41
Thanks, you say that
reinterpret_cast
is not needed at all, but how would you call fftw_plan_dft_1d
on std::vector<std::complex<double>>
without using reinterpret_cast
or c-style cast? I don't see how.– alfC
Nov 13 '18 at 3:41
|
show 2 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271883%2fproper-way-to-call-a-c-function-taking-non-const-pointer-arguments-const-cast%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
C does have
const
(since C89/C90) but some poorly written libraries do not use it in their function prototypes.– TypeIA
Nov 13 '18 at 0:07
@TypeIA, I noticed that, what should one do in those cases? break const correctness from the beginning or use
const_cast
. To be clear in this case, the only reason I know that I can pass a const pointer to this library is because of the last parameterFFTW_ESTIMATE
which promises not overwrite the data of first pointer.– alfC
Nov 13 '18 at 0:11