I want to do this conversion using C++ format, it works on the C way. but it fails when I try on C++ format.
It works!
void req_password(const void *data, size_t datalen)
{
char *password_old = ((char **) data)[0];
char *password_new = ((char **) data)[1];
...
}
It fails
void req_password(const void *data, size_t datalen)
{
char *password_old = (const_cast<char **>(data))[0];
char *password_old = (const_cast<char **>(data))[1];
...
}
error:
error: invalid const_cast from type 'const void*' to type 'char**'
So my doubt is, how could I do this conversion using the C++ way?
PS: This code is part from a API, I can't control the the input of data.
Don't.
If you are being given immutable data, then you are being given immutable data and that is the end of it!
First, here's what I suggest for maximum safety. Coercing data into its real type is a little tricky, alas:
void req_password(const void* data, size_t datalen)
{
const char* password_old = (reinterpret_cast<const char* const*>(data)[0]);
const char* password_new = (reinterpret_cast<const char* const*>(data)[1]);
// ...
}
(I've actually added some constness in the above, as it seems to be the intent of having const void* in the first place.)
But, if you really want the strings to be mutable, then this is fine too:
void req_password(const void* data, size_t datalen)
{
char* password_old = (reinterpret_cast<char* const*>(data)[0]);
char* password_new = (reinterpret_cast<char* const*>(data)[1]);
// ...
// More obvious when you recall that `const void*` is actually `void const*`;
// So:
// void const*
// becomes:
// char* const*
}
Notice how you don't even need const_cast here, because you're not modifying the thing that data points to: you are dereferencing it and getting its pointee.
Of course, ideally, data would point to a const std::string instance.
Related
I have a macro:
#define checkAlloc(ans) checkPointer((ans), __FILE__, __LINE__);
which is used to wrap around any pointer allocation to check it is valid (used for checking memory allocations on a GPU device side).
The macro is used as follows:
SomeObject* myObj = checkAlloc(new SomeObject());
and the checkPointer function is implemented as:
inline __device__ SomeObject* checkPointer(SomeObject* pointer, char *file, int line)
{
if (pointer == nullptr)
{
// do error logging
}
return pointer;
}
Now, it is very inconvenient to create a new version of the function for each type of object I might allocate to. Templates are also not an option since I would like syntax to be clear - i.e. just putting checkAlloc(…) around each allocation rather than checkAlloc<SomeObject>(…) which is ugly and hopefully unnecessary.
Ideally I would like to change the checkPointer to be:
inline __device__ auto checkPointer(auto pointer, char *file, int line)
but I understand auto cannot be used for a function parameter yet. The GPU code supports C++14 so lambdas could be used as a potential workaround from I can read at https://stackoverflow.com/a/29945034/7283981 but I am not familiar enough with lambdas to know how to do this. Any ideas?
This is the perfect case for a template, I don't understand why you are trying to avoid it:
template < typename T >
inline __device__ T* checkPointer(T* pointer, const char *file, int line)
{
if (pointer == nullptr)
{
// do error logging
}
return pointer;
}
This is very clear and clean and you can use it as if there was an auto there:
int main(int argc, char** argv)
{
SomeObject* myObj = checkAlloc(new SomeObject());
}
As you can see, there are automatic argument deduction capabilities that don't even require any type specification...
Oh, and notice that I changed char * file to const char * file as C++11 doesn't allow conversion of literals to char *
I'm trying to make a function that takes a void*, copies some memory to it, and then moves the pointer.
Since it is a void pointer, I thought I'd cast it to char* and move that, like so:
PVOID SendAndMoveHead(PVOID dest, const Message& message, const size_t& size)
{
PVOID ret = CopyMemory(dest, (PVOID)message.msg.c_str(), size);
((char*)dest) += size;
return ret;
}
However, VS complains about ((char*)dest) saying
expression must me a modifiable lvalue
which I thought it was, since the following works:
PVOID SendAndMoveHead(PVOID dest, const Message& message, const size_t& size)
{
PVOID ret = CopyMemory(dest, (PVOID)message.msg.c_str(), size);
char* d = (char*)dest;
d += size;
return (PVOID)d;
}
If someone could shed some light on why the first version shouldnt work I'd really appreciate it.
((char*)dest) gives you a new temporary char *. ((char*)dest) += size; would change the temporary and have no effect, which causes a compilation failure.
In the second example d is not a temporary and lives long enough to get returned.
Alternatively you could write return (char*)dest + size;.
I can't find the answer anywhere.
I wrote this class:
class Message {
private:
char senderName[32];
char* namesOfRecipients[];
int numOfContacts;
char subject[129];
char body[10001];
};
And I'm trying to write a constructor with default arguments like this:
Message(char senderName[32]="EVA",
char* Recipents[]={"glados","edi"},
int numOfRec=3,
char subject[129]="None",
char content[10001]="None");
However, it won't accept the recipients default argument no matter how I write it.
Is it even possible to pass a 2D array as a default argument for a constructor?
Sooo many pointers and arrays... if It is C++ why bother? Just write:
class Message {
private:
std::string senderName;
std::vector<std::string> namesOfRecipients;
int numOfContacts;
std::string subject;
std::string body;
};
And:
Message("EVA", {"glados","edi"}, 3, "None", "None");
And everbody is happy...
As Paul mentioned, you should change the declaration of namesOfRecipients to
char **namesOfRecipients;
Then you can have a private const static array of default names in the class and initialize namesOfRecipients with a pointer to its first element. The code is below.
Edit: It's important to understand what the data semantics are here, for example compared to Jarod's solution. The default ctor stores the address of an array of constant pointers to constant character strings. It's not at all possible to copy different characters into a name or to let one of the pointers in the array point to a new name, or to append a name. The only legal thing here is to replace the value of namesOfRecipients with a pointer to a new array of pointers to char.
class Message {
private:
char senderName[32];
char** namesOfRecipients;
int numOfContacts;
char subject[129];
char body[10001];
static const char* defaultNames[];
public:
Message(const char senderName[32]="EVA",
const char** Recipents = defaultNames,
int numOfRec=3,
const char subject[129]="None",
const char content[10001]="None");
};
const char *Message::defaultNames[] = {"Jim", "Joe"};
You can do something like:
namespace
{
char (&defaultSenderName())[32]
{
static char s[32] = "EVA";
return s;
}
const char* (&defaultNamesOfRecipients())[2]
{
static const char* namesOfRecipients[2]={"glados", "edi"};
return namesOfRecipients;
}
}
class Message {
private:
char senderName[32];
const char* namesOfRecipients[2];
public:
Message(char (&senderName)[32] = defaultSenderName(),
const char* (&namesOfRecipients)[2] = defaultNamesOfRecipients())
{
std::copy(std::begin(senderName), std::end(senderName), std::begin(this->senderName));
std::copy(std::begin(namesOfRecipients), std::end(namesOfRecipients), std::begin(this->namesOfRecipients));
}
};
but using std::string/std::vector would be simpler.
Use a separate array of pointers (it's not a 2-D array, though it may look like it) as a default argument:
char* defaultRecipents[] = {"glados","edi"};
class Message {
public:
Message(char senderName[32]="EVA",
char* Recipents[]=defaultRecipents){}
};
Specifying the default array "inline" doesn't work because the compiler "thinks" about it in terms of std::initializer_list, which is only suitable in initialization, not in declaration. Sorry if this sounds vague; I don't have enough experience with this matter.
Note: you might want to use const to declare your strings, to make it clear to the compiler (and your future self) whether the class is or is not going to alter the strings:
const char* const defaultRecipents[] = {"glados","edi"};
class Message {
public:
Message(char senderName[32]="EVA",
const char* const Recipents[]=defaultRecipents){}
};
Here it says const twice to declare that it's not going to:
Change the array elements (e.g. replace one array element, which is a string, by another string or nullptr); and
Change the contents of the strings (e.g. cut a string in the middle, or edit it)
void process( int boat ) { ; }
const void(*sequence_A[])( int ) = { process, process }; //ERROR
const void(**func_sequence)( int ) = sequence_A;
(*func_sequence++)( 7 );
Why won't this compile? I want const to refer to the array, not the contents of the array.
Error 1 error C2440: 'initializing' : cannot convert from 'void (__cdecl *)(int)' to 'const void (__cdecl *)(int)'
EDIT: So you guys are saying it doesn't exist. Fair enough. Just to be clear, I'm posting this analogy of the functionality I wanted but this is with int instead of function ptrs
//Compiles without error
int number1 = 7;
int number2 = 3;
const int* sequence_B[] = { &number1, &number2 };
const int** numbers = sequence_B;
int check = **numbers++; //value is 7
int chec2 = **numbers++; //value is 3
Okay, let's analyze the meaning of your statement
const void(*sequence_A[])( int ) = { process, process }; //ERROR
The way I remember the parsing of *x[] is that the second argument of main is char* argv[], so, it's an array of pointers. In other words, sequence_A is to be indexed, and then the result is to be dereferenced.
Then, to that you can apply a function call argument parenthesis with an int value, and as a result you should get a …
const void ?
Well that's not entirely meaningful. You can have a pointer to const void, but you can't dereference that pointer: you can't "get at" the const void directly. Yet here is some pointer to a function that produces as its expression value a const void.
To match that you would need
const void process( int boat ) { ; }
and although I haven't tried it, I doubt that any compiler will accept it. [Update: as it turns out, at least g++ accepts it, so it is one solution. But it's a very unconventional function signature. And not at all what you're after!]
In short, remove that const.
On a related note, as mentioned already in a comment you can't have a const raw array, except in the sense of a raw array of const items.
It's a corner case of the language, a problematic type system aberration inherited from C.
Along with the array type decay to pointer, also problematic.
Addendum: example of how to make the array items const:
void process( int boat ) { ; }
int main()
{
void(* const sequence_A[])( int ) = { process, process }; // OK
//sequence_A[0] = process; //ERROR
}
I hava a class like:
class SomeClass
{
void initFromBuffer(void* buffer,int length);
void initFromString(const std::string& str);
}
Using tolua++, got the binding like:
static int SomeClass_initFromBuffer00(lua_State* tolua_S)
{
SomeClass* self = (SomeClass*) tolua_tousertype(tolua_S,1,0);
void* buffer = ((void*) tolua_touserdata(tolua_S,2,0));
int length = ((int) tolua_tonumber(tolua_S,3,0));
self->initFromBuffer(buffer,length);
}
and:
static int SomeClass_initFromString00(lua_State* tolua_S)
{
SomeClass* self = (SomeClass*) tolua_tousertype(tolua_S,1,0);
const std::string str = ((const std::string) tolua_tocppstring(tolua_S,2,0));
self->initFromString(str);
tolua_pushcppstring(tolua_S,(const char*)str);
}
Now,i want to pass binary data from lua to c++,the binary has '\0' in it,so if i use initFromString to pass it, the binary data will be trimed. But if i use initFromBuffer to pass it, i got bad ptr at `void* buffer = ((void*) tolua_touserdata(tolua_S,2,0));, the pointer is null.
So, how could i pass binary string from lua to c++?
Maybe you should stop using Tolua's bad APIs and use plain Lua's actually good APIs. Both std::string and Lua strings are capable of storing embedded null characters. The only reason tolua_tocppstring causes truncation is because the function name is a lie. It doesn't convert it to a C++ string; it converts it to a C string, a const char*.
The correct answer is to use the proper API function:
std::string fromLuaStack(lua_State *lua, int stackIx)
{
size_t len;
const char *str = lua_tolstring(lua, stackIx, &len);
return std::string(str, len);
}
Similarly, you can use lua_pushlstring to push a std::string onto the stack.
It's unfortunate that Tolua doesn't have better documentation, as there may be a function to do this all directly. If there is, I couldn't find it.