C++ how to convert from char * to unsigned char * in function call? - c++

When building my C++ application the build fails at this line of code
if (!PyTuple_GetByte(poArgs, 0, &SourceCell.window_type))
with this error
error C2664: 'PyTuple_GetByte' : cannot convert parameter 3 from
'char *' to 'unsigned char *'
This is the called function:
bool PyTuple_GetByte(PyObject* poArgs, int pos, unsigned char* ret);
The third parameter &SourceCell.window_type is type char.
Is there a way to convert/cast the parameter inside the function call like
if (!PyTuple_GetByte(poArgs, 0, reinterpret_cast<unsigned char*>(&SourceCell.window_type)))
or do I have to deal with it in another way?

From the error, the signature of the PyTuple_GetByte function was expecting a third parameter of type unsigned char*, but you passed a variable of type char* at its invocation. I think you have two options here.
You can change the signature of function PyTuple_GetByte to expect a char* parameter.
You need to convert your input variable from type char* to type unsigned char*, before you can pass it into PyTuple_GetByte.
The conversion is normally like this:
unsigned char* convert_var = reinterpret_cast<unsigned char*>(&SourceCell.window_type); // (c++ way)
or
unsigned char* convert_var = (unsigned char*)(&SourceCell.window_type); // (c way)

Related

Converting C program to C++ with lot of char* and unsigned char conversion errors

I need to use methods described in RFC2617 and RFC1321, but am getting problems about converting C to C++. Mostly I have problem with a parameter is defined as unsigned char but argument is a char* variable.
I can solve errors with reinterpret_cast but thought there would be a better way, because there is lot of changes need to be done.
For example in the following line in md5c.c variable pszUserName is declared as char*, if the variable changed to unsigned char*, then strlen got errors:
IN char * pszUserName,
...
MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
Declaration of MD5Update
void MD5Update (
MD5_CTX *context, /* context */
unsigned char *input, /* input block */
unsigned int inputLen /* length of input block */
)
{
...
}
I got this error in the first place:
../Dig/digcalc.cpp: In function ‘void DigestCalcHA1(char*, char*, char*, char*, char*, char*, char*)’:
../Dig/digcalc.cpp:44:58: error: invalid conversion from ‘char*’ to ‘unsigned char*’ [-fpermissive]
MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
There is also a nice copy in Github
Technically, char, unsigned char and signed char are types incompatible with each other. The code:
MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
"should" be:
MD5Update(&Md5Ctx, (char *)pszUserName, strlen(pszUserName));
However, in my opinion, this is all rather annoying. MD5Update works equally well on char as unsigned char; we shouldn't have to make the code less readable for no real reason.
On existing codebases that use char * and unsigned char * interchangeably like this, I enable the compiler flag -Wno-pointer-sign and don't feel bad about it. It keeps the code more readable and the compiler behaves as if there were a cast.

unsigned char array incompatible with pointer parameter

I have this function
unsigned char NCN_System_upload(unsigned char *data, unsigned char len);
I have an array defined as such:
unsigned char data[3];
I'm using the function as the following:
NCN_System_upload(&data, 3);
However, I get the following error:
argument of type unsigned char (*)[3] is incompatible with parameter of type unsigned char*
Why doesn't this work?
The name of the array is already (can be implicitly converted) to a pointer to its beginning. Thus, you should do it like this:
NCN_System_upload(data, 3);

Conversion from 'const char *' to 'unsigned char *' in C++?

I have an encryption function declared as follows: int encrypt(unsigned char* keydata, int keydata_len, unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext). This works perfectly and now I call it according to the given snippet.
const char *password = "password";
len = encrypt(password, (int)strlen(password), (unsigned char*)(content.c_str()), (int)strlen(content.c_str()), ciphertext);
On compiling the C++ code I get an error as:
crest.cc:52:13: error: no matching function for call to 'encrypt'
len = encrypt(password, (int)strlen(password), (unsigned char*)(content.c_str()), (int)strlen(content.c_str()), ciphertext);
^~~~~~~
./aes.h:10:5: note: candidate function not viable: no known conversion from 'const char *' to 'unsigned char *' for 1st argument
int encrypt(unsigned char* keydata, int keydata_len, unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext);
What is the correct way to typecast in C++ to get around this error ?
There are several problems with this code, and the only (correct) way to fix them is to ensure that you use the correct data types in the first place.
So, instead of const char *password = "password", use unsigned char password[] = "password"; (of course, this will probably give you trouble with strlen, since it won't like unsigned char) - using sizeof(password)-1 will work in THIS instance, but is ill advised as a general solution, since password may well be not be directly available as an array - not sure quite what you should do as an "ideal" solution, really.
Now, the question can be asked whether it is actually correct to have a non-const input to the function. If you have the source for encrypt, you may want to change the function to encrypt(const unsigned char* keydata, size_t keydata_len, const unsigned char* plaintext, size_t plaintext_len, unsigned char* ciphertext) - still doesn't fix the problem with strlen of unsigned char of course, but it's what I'd expect the prototype to be for a function like this.
An alternative would be to rewrite the encrypt function to make casts to unsigned only internally, and use char * inputs (with const where relevant).
Note that it's NOT valid to cast away constness EXCEPT for cases where you know that the original content is not const (which I think is NOT guaranteed to be the case for std::string::c_str(), but std::string::data() should work)

How to initialize "unsigned char *" with default argument in C++?

I have a class with a method with the following signature:
void print(unsigned char *word);
I need to set "" as default value for word, how can I do that?
I tried the obvious void print(unsigned char *word=""); but I got the following error:
error: cannot initialize a parameter of type
'unsigned char *' with an lvalue of type 'const char [1]'
void print(unsigned char *word="");
Since I can't initialize word with a string literal who should I do it?
You say that this is a "prefix" argument to apply to the printing.
The answer is that you should make the argument const, stop doing whatever mutations you're doing to it inside the function, and then use "" as a default argument:
void print(const char* prefix = "")
try
unsigned char empty[] = { 0 };
void print(unsigned char* word = empty )
{
...
}
"" yields an array of const char, whereupon you want an array of or pointer to NON-const unsigned char, both the type and the cv-qualification don't fit.
Note also that in C++ char != signed char and char != unsigned char.
Possibly you mean void print(const char *word);, but probably you want just print(std::string const &) or print(std::string).
void print();
void print(unsigned char* prefix);
// in cpp file:
void print(){
unsigned char temp = 0;
print(&temp);
}
This provides two overloads, one with 0 and one eith one argument.
The zero argument one has some automatic storage memory it provides to the one argument one. Note that only the single byte under the pointer is valid to read/write: without a length, print has no way to know any different anyhow.
While there is no array, none is needed for a single element.

C code in C++ compiler

I have following code, it's code from tomcrypto's manual and it won't work on MS VC++ 2008 EE. Any help? Also can I ask replace char* by std::string object?
int main(void)
{
hash_state md;
unsigned char *in = "hello world", out[16];
/* setup the hash */
md5_init(&md);
/* add the message */
md5_process(&md, in, strlen(in));
/* get the hash in out[0..15] */
md5_done(&md, out);
return 0;
}
Errors:
\main.cpp(7) : error C2440: 'initializing' : cannot convert from 'const char [12]' to 'unsigned char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
.\main.cpp(11) : error C2664: 'strlen' : cannot convert parameter 1 from 'unsigned char *' to 'const char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
EDIT: Now code looks like:
int main(void)
{
register_hash(&md5_desc);
hash_state md;
char* p = "hello wordl";
unsigned char *in = reinterpret_cast<unsigned char*>(p);
char* out[16];
/* setup the hash */
md5_init(&md);
/* add the message */
md5_process(&md, const_cast<char*>(in), strlen(in));
/* get the hash in out[0..15] */
md5_done(&md, out);
return 0;
}
Errors:
\main.cpp(21) : error C2440: 'const_cast' : cannot convert from 'unsigned char *' to 'char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
.\main.cpp(21) : error C2664: 'strlen' : cannot convert parameter 1 from 'unsigned char *' to 'const char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
.\main.cpp(23) : error C2664: 'md5_done' : cannot convert parameter 2 from 'char *[16]' to 'unsigned char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
unsigned char *in = "hello world"
This is incorrect in C++: "hello world" is a string literal and is of type const char[12]. In C it is of type char[12], but the const here doesn't matter because in C++ there is an implicit (but deprecated) conversion that allows a string literal to be converted to a char*.
The problem is that char and unsigned char are different types. It doesn't matter whether char is unsigned; the three char types (char, unsigned char, and signed char) are all distinct and in C++ you cannot convert between pointers to those three types without a cast.
This works in C because in C you can convert any pointer-to-object type to any other pointer-to-object type without a cast. That isn't the case in C++.
In C++ you would need to use:
// use the implicit conversion to 'char*' to cast away constness:
char* p = "hello world";
// explicitly cast to 'unsigned char*'
unsigned char* in = reinterpret_cast<unsigned char*>(p);
The removal of constness is usually a bad idea since string literals are not modifiable, but sometimes it is necessary when dealing with legacy libraries that are not const-correct.
The conversion from char* to unsigned char* is safe because all objects can be treated as an array of char, unsigned char, or signed char in C++.
char is a different type to signed char or unsigned char; string literals are always of type (const) char *; so you cannot assign them to a (const) signed char * or a (const) unsigned char *. To fix this, remove the unsigned from line 4.
If your md5_process() function explicitly takes an unsigned char * as an argument, then you should perform a cast at that point:
md5_process(&md, reinterpret_cast<unsigned char*>(in), strlen(in));
[As others have said, you should really define in as const char *in as it's pointing to a string literal, but that is not the issue here.]
Let's try again:
int main(void)
{
register_hash(&md5_desc);
hash_state md;
const char* p = "hello wordl";
const unsigned char* in = reinterpret_cast<const unsigned char*>(p);
unsigned char out[16];
/* setup the hash */
md5_init(&md);
/* add the message */
md5_process(&md, in, strlen(p));
/* get the hash in out[0..15] */
md5_done(&md, out);
return 0;
}
Does this work?
This is because litteral strings are const in C++, while you initialize it with a non-const pointer:
const char* in = "hello world";
char * out[16];
However it might cause a problem if md5_process takes a non-const char*, in this case you'll have to cast to a non-const:
md5_process(&md, const_cast<char*>(in), strlen(in));