What C++ casts is the C cast using in order to convert from a const void* to a unsigned char*?
auto ucharptr = (unsigned char*)const_void_ptr;
Try the C++ casting operator and you need two of them: one to remove the const and another one to cast to your pointer type:
auto ucharptr = reinterpret_cast<unsigned char*>(const_cast<void*>(const_void_ptr));
Try this:
const void* ptr = "test example";
auto ucharptr = static_cast<const unsigned char*>(ptr);
//to remove the const ness
unsigned char* test = const_cast<unsigned char*>(ucharptr);
The easiest way to do that would probably be the following:
unsigned char* ucharptr = reinterpret_cast<unsigned char*>(const_cast<void*>(const_void_ptr));
Related
I have variable input type const std::string&:
const std::string& input
Now I need to convert this to const unsigned char* because this is the input of the function.
Unitl now I have correct code for converting:
reinterpret_cast<const unsigned char*>(input.c_str())
This works well, but in clang I got a warning:
do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
What is the correct way to change a string or const char* to const unsigned char*?
What is the correct way to change a string or const char* to const unsigned char*?
The correct way is to use reinterpret_cast.
If you want to avoid reinterpret_cast, then you must avoid the pointer conversion entirely, which is only possible by solving the XY-problem. Some options:
You could use std::basic_string<unsigned char> in the first place.
If you only need an iterator to unsigned char and not necessarily a pointer, then you could use std::ranges::views::transform which uses static cast for each element.
You could change the function that expects unsigned char* to accept char* instead.
If you cannot change the type of input and do need a unsigned char* and you still must avoid reinterpret cast, then you could create the std::basic_string<unsigned char> from the input using the transform view. But this has potential overhead, so consider whether avoiding reinterpret_cast is worth it.
Edit
Apparently type punning with an union is UB so definitely don't do this.
(Keeping the answer for posterity though!)
To strictly answer your question, there's this way:
void foo(const unsigned char* str) {
std::cout << str << std::endl;
}
int main()
{
std::string word = "test";
//foo(word.data()); fails
union { const char* ccptr; const unsigned char* cucptr; } uword;
uword.ccptr = word.data();
foo(uword.cucptr);
}
Is this any better than a reinterpret_cast? Probably not.
I am currently working with a C-API (OpenSSL) and there are a lot functions declared like the following:
// From bytes to TYPE
TYPE *d2i_TYPE(TYPE **a, unsigned char **ppin, long length);
// From TYPE to bytes
int i2d_TYPE(TYPE *a, unsigned char **ppout);
But sometimes, functions expect a pointer to an array of pointers to some const type:
// From bytes to TYPE
TYPE *d2i_TYPE(TYPE **a, const unsigned char **ppin, long length);
Notice the const unsigned char ** vs unsigned char ** and ignore the functions' first argument.
Now consider the following example, where some input data is given as non-const pointers. What is the correct way of casting the array of pointers to an array of pointers const? And also, since the function expects a pointer, the parameter must be an lvalue. I am guessing this is the reason there is no implicit cast..
int length = 42;
unsigned char * data = new unsigned char[length];
// Error C2664: cannot convert argument 2 from 'unsigned char **' to 'const unsigned char **'
TYPE * my_typeE = d2i_TYPE(nullptr, &data, length);
// My solution:
auto x = reinterpret_cast<unsigned char const *>(data);
auto y = const_cast<unsigned char const *>(data);
TYPE * my_typeX = d2i_TYPE(nullptr, &x, length);
TYPE * my_typeY = d2i_TYPE(nullptr, &y, length);
Are there other solutions that are possibly easier to read?
No need of cast:
const unsigned char* z = data;
[[maybe_unused]]TYPE * my_typeZ = d2i_TYPE(nullptr, &z, length);
Demo
I'm wondering why this code works in C and not in C++
void* dum;
dum = "dum";
I have the C++ error
In function 'int main()':
8:10: error: invalid conversion from 'const void*' to 'void*' [-fpermissive]
Any C++ equivalent?
I'm wondering why this code works in C and not in C++
It doesn't work in C++ because string literal is an array of const char.
Any C++ equivalent?
const char* dum = "dum";
void* dum;
dum = (void *)"dum";
const void* dum = "dum";
const char* dum = "dum";
const char* dum;
dum = "dum";
const void* dum;
dum = "dum";
You would have to cast it back to get the result you want.
String literals have type const char* so your pointer would need to be constalso. You cannot assign something that is const to a pointer to non const.
const void* dum = "dum";
cout << static_cast<const char*>(dum);
Try this coutwithout the cast to see what you get. It would be interpreted as a void pointer...
According to these answers a buffer of bytes should be unsigned char, either because of convention or maybe the padding guarantees, I'm not sure. I have a function that looks something like:
saveDataToFile(const unsigned char* data, size_t size);
I find that I keep having to cast when I have a vector of char or an std::string or a string literal or something, and my code ends up looking like:
const char* text = "text";
saveDataToFile(text, 4); // Argument of const char* is incompatible with parameter of type const unsigned char*
saveDataToFile(reinterpret_cast<const unsigned char*>(text), 4);
Is there a way to avoid doing this all the time? Someone once mentioned to make my function take const char* instead of unsigned, but that doesn't really as then I'd have to cast the other way. For example std::string has .c_str() and .data() that return signed and unsigned. I also thought about taking void*, maybe that's the best way?
Perhaps the simplest way, as you have suggested yourself, is to make the function's first argument a const void* and then cast that to whatever is needed inside the function. This way, you also avoid using a reinterpret_cast and can safely use a static_cast:
void saveDataToFile(const void* data, size_t size)
{
const uint8_t* local = static_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}
int main()
{
double dData = 33.3;
int16_t sData = 42;
char cData[] = "Hello, World!";
saveDataToFile(&dData, sizeof(dData));
saveDataToFile(&sData, sizeof(sData));
saveDataToFile(cData, sizeof(cData));
return 0;
}
A more "Pure C++" way (in some folks' eyes, maybe) would be to make a templated function. However, the disadvantages here are: (a) you will need a reinterpret_cast in this case; and (b) the compiler will (probably) generate separate function code for each of the different argument types used:
template<typename T>
void saveDataToFile(const T* data, size_t size)
{
const uint8_t* local = reinterpret_cast<const uint8_t*>(data);
//.. do something with the cast pointer ...
}
entire code is below link.
base64 decode snippet in c++
I have a question about const pointer in above link code.
main
std::vector<BYTE> myData;
...
std::string encodedData = base64_encode(&myData[0], myData.size());
base64_encode
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
int j = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *(buf++);
if (i == 3) {
parameter is BYTE const* buf, not const BYTE* buf.
when const BYTE* buf is used as parameter,
const is for BYTE, so pointer can be changed but the value of buffer can not be changed.
when BYTE const* buf is used, const is for pointer variable, so value can be changed but address can not be changed.
in above code,
buf pointer is const, but buf++ is possible?
and why BYTE const* buf is used instead of const BYTE* buf?
thanks
Confusingly, const BYTE* and BYTE const* are equivalent to each other. Both are pointers-to-const.
To make the pointer itself const, the formulation is BYTE *const. A const pointer-to-const would be BYTE const *const or const BYTE *const.
I cannot speculate as to why the authors of this function chose the BYTE const* version instead of the much more popular const BYTE*.