when const pointer is used as parameter of function - c++

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*.

Related

Cast C-style array of pointers to const

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

If buffer of bytes should be unsigned char do I have to keep casting all the time?

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 ...
}

Change uint8_t* to char*?

I have an API which requests a char*, this is my API function:
CANMessage(unsigned _id, const char* _data, char _len = 8)
More information available here: https://os.mbed.com/docs/mbed-os/v5.11/mbed-os-api-doxy/classmbed_1_1_c_a_n_message.html
I would like to call this function from within another function, but I am getting confused about const char* and casting. I want to call this function from function foo(), like so:
void foo(unsigned int id, /*???*/ data, char len) {
CANMessage(id, data, len)
}
So I need to pass id, data and len to function foo. My problem is that the data coming in is a uint8_t type. I got a vector of uint8_t, where the address of the first element is the one I need to pass:
vector<uint8_t> dta;
Which I tried to pass as &dta[0]: foo(idNo, &dta[0], length)
With the foo function as so:
void foo(unsigned int id, uint8_t* data, char len) {
CANMessage(id, (char*)data, len)
}
But I get "Argument of type std::uint8_t * is incompatible with parameter of type char*
How do I pass it as const char* when function foo, which calls it, accepts uint8_t*?
Please note I can't change types, dta has to stay vector<uint8_t>.
std::uint8_t ιs equal to unsigned char.
This is different from plain char or signed char, but all of them are 8 bit, therefore casting would techically work.
It's common that many functions that would otherwise need a "buffer" have a char* in their definition instead of the proper unsigned char*. Therefore, casting would most probably be harmless.
In the case that the function actually wants characters but not a buffer, then you have a problem because the types are different, and whether you will have an issue or not is undefined.
Since you are in an environment where std::uint8_t is available, the char types must be max 8 bits, but just to make sure you're not on a machine with 7 bit char's, add a static_assert.
reinterpret_cast the uint8_t* to const char* and static_cast the size (size_t) of the vector to char.
void foo(unsigned _id, const std::vector<uint8_t>& dta) {
static_assert(CHAR_BIT == 8, "Strange char");
CANMessage(
_id,
reinterpret_cast<const char*>(dta.data()),
static_cast<char>(dta.size())
);
}

How to use C functions in Qt C++

I am a web developer and I am new to C++. I am using Qt C++. I was looking a way to generate a PBKDF2 key in Qt, but could not find a way to do that in pure C++. So looking on internet I have found this small C implementation https://github.com/ctz/fastpbkdf2. I need to use the following function
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
In my C++ file, I have
QString password = "password";
QString salt = "salt";
int iterations = 30000;
I know I can directly call any C function in C++, but I am not sure about how can I call that function with those parameters from my C++ file. An explanation of data type conversions would also be appreciated.
All you need to convert QString to char (or uint8_t):
QString passoword = "password";
QByteArray ba = password.toLatin1();
const uint8_t *pw = (const uint8_t*)ba.data();
And you can use this pw in the function. The same for "salt". You can use "iterations" as it is. For "out" parameter, allocate uint8_t with any method you prefer, could be malloc.
uint8_t is a typedef for an unsigned 8-bit integer, or in other words an unsigned char.
uint32_t is a typedef for an unsigned 32-bit integer, or in other words an unsigned int.
These typedefs are defined in stdint.h. These types were introduced to have well-defined (width-wise) integer types for portability.
size_t is typically an unsigned integer type as well. So the
prototype:
void fastpbkdf2_hmac_sha256(const uint8_t *pw, size_t npw,
const uint8_t *salt, size_t nsalt,
uint32_t iterations,
uint8_t *out, size_t nout)
is equivalent to:
void fastpbkdf2_hmac_sha256(const unsigned char* pw, unsigned int npw,
const unsigned char* salt, unsigned int nsalt,
unsigned int iterations,
unsigned char* out, unsigned int nout);
Others have posted how to convert QString into a unsigned character array.
I am not too familiar with QT so I am looking at this page as a reference for a QString. It appears to be a managed string object while the function you want to call just wants a null terminated array of uint8_ts. I think it is wrapping std::string because there is a toStdString() member function. A std::string just manages a character array which is what your function wants so you can do this: password.toStdString().c_str() to get the char *.
Most platforms will implicitly convert uint8_t and char since they are almost always straight up 1 byte of memory.
There is also an output buffer and by the calling convention it looks like you have to manage that memory. From glancing at the docs of the github you linked it will output however much memory you tell it to using nout. In this example we create a 256 byte buffer for it to output to.
QString password = "password";
QString salt = "salt";
int iterations = 30000;
const size_t nout = 256;
uint8_t * out = new uint8_t[nout];
fastpbkdf2_hmac_sha256(password.toStdString().c_str(), password.toStdString().size(),
salt.toStdString().c_str(), salt.toStdString().size(),
iterations,
out, nout);
// use out
delete[] out;

How to let a uint8_t const* point at the same address as a char*?

In a C++-program I have a char* pointing to the beginning of an array containing BUFFER_SIZE number of chars (each char the size of one byte).
I now want to use that code in an NS3-simulation, which packets takes as input a uint8_t const* , pointing to a buffer.
What should I do in order to create a 'uint8_t const*' which points at the first mentioned buffer?
You must either use reinterpret_cast:
int main () {
char buffer[10];
reinterpret_cast<unsigned char const *>(buffer);
}
or use a C-style cast:
int main () {
char buffer[10];
(unsigned char const *)buffer;
}