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;.
Related
With the following snippet:
int n = 11;
int* c = &n;
void** v = &c;
I receive the following error in visual studio:
the value of type int** cannot be used to initialize an entity of type void **.
This works fine:
int n = 11;
int* c = &n;
void* v = c;
But this code snippet is for a larger problem in someone's library.
What am I doing wrong with casting a variable to void**?
Complete Example
Using the caen digitizer library the way they try to collect data from the peripheral device has this prototype:
/******************************************************************************
* X742_DecodeEvent(char *evtPtr, void **Evt)
* Decodes a specified event stored in the acquisition buffer writing data in Evt memory
* Once used the Evt memory MUST be deallocated by the caller!
*
* [IN] EventPtr : pointer to the requested event in the acquisition buffer (MUST BE NULL)
* [OUT] Evt : event structure with the requested event data
* : return 0 = Success;
******************************************************************************/
int32_t X742_DecodeEvent(char *evtPtr, void **Evt);
And this is the implementation:
int32_t X742_DecodeEvent(char *evtPtr, void **Evt) {
CAEN_DGTZ_X742_EVENT_t *Event;
uint32_t *buffer;
char chanMask;
uint32_t j,g,size;
uint32_t *pbuffer;
uint32_t eventSize;
int evtSize,h;
evtSize = *(long *)evtPtr & 0x0FFFFFFF;
chanMask = *(long *)(evtPtr+4) & 0x0000000F;
evtPtr += EVENT_HEADER_SIZE;
buffer = (uint32_t *) evtPtr;
pbuffer = (uint32_t *) evtPtr;
eventSize = (evtSize * 4) - EVENT_HEADER_SIZE;
if (eventSize == 0) return -1;
Event = (CAEN_DGTZ_X742_EVENT_t *) malloc(sizeof(CAEN_DGTZ_X742_EVENT_t));
if (Event == NULL) return -1;
memset( Event, 0, sizeof(CAEN_DGTZ_X742_EVENT_t));
for (g=0; g<X742_MAX_GROUPS; g++) {
if ((chanMask >> g) & 0x1) {
for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
Event->DataGroup[g].DataChannel[j]= malloc(X742_FIXED_SIZE * sizeof (float));
if (Event->DataGroup[g].DataChannel[j] == NULL) {
for (h=j-1;h>-1;h++) free(Event->DataGroup[g].DataChannel[h]);
return -1;
}
}
size=V1742UnpackEventGroup(g,pbuffer,&(Event->DataGroup[g]));
pbuffer+=size;
Event->GrPresent[g] = 1;
}
else {
Event->GrPresent[g] = 0;
for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
Event->DataGroup[g].DataChannel[j] = NULL;
}
}
}
*Evt = Event;
return 0;
}
I use this by:
CAEN_DGTZ_X742_EVENT_t* Evt = NULL; // Creating my event pointer
//Doing some config of the device
X742_DecodeEvent(evtptr, &Evt); //Decode the event data for me to read (Throws error)
Hope this gives some context.
void** means a pointer to a void* object. But there is no void* object in that code to point at! void** does NOT mean "a pointer to any kind of pointer", so please avoid using it as such. If you have a pointer to something which might be an int*, might be a double*, or etc., void* is a better type than void**. Even better would be a template or std::variant or std::any.
But if you have to use a library that is using void** to mean "a pointer to a pointer to a type unknown at compile time" or something like that, you might need to create a void* pointer to work with, or might need to add in casts to get around the fact that the compiler doesn't like this conversion (for good reason). The problem is, there are at least two reasonable ways to do this! (They will end up doing exactly the same thing on many common computer architectures, but this is not guaranteed.)
// LibraryFunc1 takes a void** argument that somehow means an int* pointer.
// But which call is correct?
int* data_in = generate_data();
LibraryFunc1(reinterpret_cast<void**>(&data_in)); // ?
void* p1 = data_in;
LibraryFunc1(&p1); // ?
// LibraryFunc2 returns a void** argument that somehow means an int* pointer.
void** p2 = LibraryFunc2();
int* data_out_1 = static_cast<int*>(*p2); // ?
int* data_out_2 = *reinterpret_cast<int**>(p2); // ?
Based on the function definition shown, the safe usage is unfortunately:
void* tmpEvt;
X742_DecodeEvent(evtptr, &tmpEvt);
auto* Evt = static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);
since the library function assumes at *Evt = Event; that *Evt is actually a void* object it can modify. It may usually work to do the simpler thing instead:
CAEN_DGTZ_X742_EVENT_t* Evt = NULL;
X742_DecodeEvent(evtptr, reinterpret_cast<void**>(&Evt));
but this is undefined behavior by the C++ Standard, and might do the wrong thing on some architectures.
You could make the correct way easier by wrapping it in a function:
inline CAEN_DGTZ_X742_EVENT_t* Get_X742_DecodeEvent(char* evtPtr)
{
void* tmpEvt;
X742_DecodeEvent(evtPtr, &tmpEvt);
return static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);
}
What am I doing wrong with casting a variable to void**?
There is no meaningful way to convert int** to void**, so what you're trying to do is wrong.
What you may do is
int n = 11;
void* c = &n;
void** v = &c;
But without a complete example, it is not possible to say whether applies to your problem.
That's simply how the language works.
void * pointers get special treatment: a pointer to an arbitrary type can be converted to a pointer to void (as long as doing so doesn't remove cv-qualifiers from the pointer).
void ** gets none of that special treatment. It's just a regular pointer type, like int **.
int32_t X742_DecodeEvent(char *evtPtr, void **Evt)
Since you want to pass CAEN_DGTZ_X742_EVENT_t ** to your function, you should change the parameter type accordingly: CAEN_DGTZ_X742_EVENT_t **Evt.
In comments you were suggested to use void ** v = (void**)&c;.
While you could probably make it work in practice, strictly speaking any access to *v would violate strict aliasing and cause undefined behavior. I wouldn't use that solution.
Lets have following function:
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0;
switch (srcType)
{
case MyType_Usint: value = (uint32b)*(uint8b*)src; break;
case MyType_Uint: value = (uint32b)*(uint16b*)src; break;
case MyType_Udint: value = *(uint32b*)src; break;
case MyType_Ulint: value64 = *(uint64b*)src; break;
}
// now encode value to dest
}
I have passed wrongly aligned uint8b Data[sizeof(uint64b)]as src, I will fix the alignment.
But I received a demand to cast Data when calling the function to proper type, i.e. encode(dest, MyType_Uint, (uint16b*)Data), which I think would cause in some more annoying unnecessary switches.
It's working even with the wrong alignment on platforms accessible for me, but I'm not sure, how it affects the other.
Would such cast fix alignment and/or endianess?
And yes, I really need the void* parameter.
encode(dest, MyType_Uint, (uint16b*)Data)
Would such cast fix alignment and/or endianess?
Such cast does not fix alignment nor endiannes.
The way to call that function without undefined behaviour is following:
uint16b u = some_value;
encode(dest, MyType_Uint, &u);
uint64b ul = some_other_value;
encode(dest, MyType_Ulint, &ul);
Does such cast actually do anything?
Such cast changes the type of the expression. In this case, the C style explicit conversion does reinterpret cast.
The converted pointer can be used only in limited ways. You can convert it back to the original type (uint8b* in your case). Indirection through the pointer is UB in most cases, with few exceptions, which include pointer-interconvertible objects, as well as using a pointer to a narrow character type as the result of the conversion. There is no exception that would apply to your example, so it would have UB.
Note that for some pointers, the C style explicit conversion does static cast, rather than reinterpret cast. For example, when the pointers are to classes in the same inheritance hierarchy. This is why C style casts are to be avoided: Use the cast that you intend to use.
Casting a pointer never fix alignment nor endianness. It just re-interpret the address as pointing to a different type, and standard does not allow to de-reference it unless an object of the appropriate type lies at that address.
The conformant way to use a possibly misaligned representation is to use memcpy:
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0;
switch (srcType)
{
// any object can be accessed through a char pointer
case MyType_Usint: uint8b tmp8 = *(uint8b*)src; value = tmp8; break;
// use a temporary for 16 bits type (endianness question)
case MyType_Uint: uint16b tmp16; memcpy(&tmp16, src, sizeof(tmp16));
value = tmp16; break;
// directly memcpy into the value when size is the same
case MyType_Udint: memcpy(&value, src, sizeof(value)); break;
case MyType_Ulint: memcpy(&value64, src, sizeof(value64)); break;
}
// now encode value to dest
}
Intel type (80x86 to core) are known to be tolerant to misalignment, but other processors are not and raise an error if you attempt a misaligned access.
This code is unlikely to work on platform that can't do unaligned memory access (like ARM9/ARM64 etc...).
This is because when you do value64 = *(uint64b*)src you expect the CPU to access a 8 bytes word (and as such it must be aligned to 64bit address) and the signature of the function does not guaranty this.
Typically, on such platform, calling:
char s;
int a = encode(dest, MyType_Ulint, &s);
will compile, and will crash at runtime (but will run ok on x86/amd64 system, yet with undefined behavior).
If you want something portable, you should do something like this:
enum MyType
{
MyType_Usint,
MyType_Uint,
MyType_Udint,
MyType_Ulint
};
int encode(uint8b *dest, MyType srcType, const void *src)
{
uint32b value = 0;
uint64b value64 = 0; // This is guaranted to be aligned for 64bit access
size_t expected_operand_size[] = { 1, 2, 4, 8 };
memcpy(&value64, src, expected_operand_size[(int)srcType]);
switch (srcType)
{
case MyType_Usint: value = *(uint8b*)&value64; break;
case MyType_Uint: value = *(uint16b*)&value64; break;
case MyType_Udint: value = *(uint32b*)&value64; break;
case MyType_Ulint: break;
}
// now encode value to dest
}
By the way, you should use template code here for convenience and to avoid the (useless) copy and be easier to understand (no need to have an type enum) :
template <typename T>
struct Encode
{
static uint64b convert(const void * src) { T t; memcpy(&t, src, sizeof(t)); return t; }
static uint64b convert(const T * src) { return *src; }
};
// Specialisation when we can avoid the copy
template <>
struct Encode<uint8b>
{
static uint64b convert(const void * src) { return (uint8b)*src; }
static uint64b convert(const uint8b * src) { return *src; }
};
template <typename T>
int encode(uint8b * dest, const void* src)
{
uint64b value64 = Encode<T>::convert(src);
// your encoding code here
}
// Use like this:
void * s = ...;
uint16b * s2 = ...;
uint32b * s3 = ...;
encode<uint8b>(dest, s); // No copy, calls Encode<uint32b>::do(const void*)
encode<uint16b>(dest, s2); // No copy, calls Encode<uint16b>::do(const uint16b*)
encode<uint32b>(dest, s3); // No copy, calls Encode<uint32b>::do(const uint32b*)
// or this is also safe
encode<uint16b>(dest, s); // Copy here for fixing alignment
I have a function (func1) that gets as a parameter a const pointer.
The value of this pointer is used for a second function (func2).
Depending on a boolean I want to modify this value before handing it to func2 or not. If I have to modify it I allocate new memory to store the modified version of it. Because in reality the const int pointer is a big array, I don't want to copy it.
I tried to solve it that way:
void func1(const int* value, bool change)
{
int* valueToUse;
if(change)
{
int changedValue = (*value)++;
valueToUse = &changedValue;
}
else
{
valueToUse = value; // <= here the Error occurs
}
func2(valueToUse);
}
void func2(const int* foo)
{
// ...
}
But if I do it this way, I get an error because I assign a const pointer to a simple pointer:
error: invalid conversion from 'const int* to int*'
Is there any easy way to solve this?
I can imagine a solution with two extra functions for each case or a version that calls func2 at two points. But because this presented code is only a very simplified version of my real code, I'm wandering if there is an easier solution to that.
Best would be a solution that works for C and C++.
Thanks guys in advance!
This works?
void func1(const int* value, bool change)
{
const int* valueToUse;
int changedValue;
if(change)
{
changedValue = (*value) + 1;
valueToUse = &changedValue;
}
else
{
valueToUse = value;
}
func2(valueToUse);
}
A const int* is a pointer to const int, which is not a const pointer to int. Therefore the pointer itself is free to change.
Also, incrementing (*value) is an error because *value is a const int.
In func1, you can make 2 calls to func2, this way there is no copy when not needed and the original value is never changed:
void func1(const int* value, bool change)
{
if(change)
{
int changedValue = *value+1;
func2(&changedValue);
}
else
{
func2(value);
}
}
void func1(const int* value, int change)
{
int* valueToUse;
if(change)
{
(*(int*)value)++;
valueToUse = (int*)value;
}
else
{
valueToUse = (int*)value; // <= here the Error occurs
}
func2(valueToUse);
}
But you don't really need this valueToUse, it's what i think, so.
void func1(const int* value, int change)
{
if(change)
(*(int*)value)++;
func2(value);
}
const int* value
This means pointer to a constant int value. It is not permitted to change the value of a constant int.
There are two ways of solving this.
Change signature of first function void func1(int* value, bool change)
Pass arguments to func1 after constant casting using const_cast and change
int changedValue = (*value)++; to int changedValue = *value + 1;
Well, running this code i receive just a warning, though i think that type conversion will help you.
valueToUse = (int*)value;
Here are some sample classes to reproduce the situation I'm facing:
class A {
B* seccond;
}
class B {
int * number;
}
static NTSTATUS Read(std::uintptr_t address, size_t size, PVOID buff);
// Let's assume we have object 'obj' which has valid address of number variable
int buff;
Read(obj.seccond, sizeof(int), &buff);
Error: cannot convert argument 1 from 'int *' to 'uintptr_t'
I know it can be fixed easily with:
Read(std::uintptr_t(obj.seccond), sizeof(int), &buff);
but this is not satisfying enough, since it lowers code readability and it's just ugly. I really don't want to use templates since they're already everywhere all over my code.
Is there any simple container for such variables? Or some more elegant way of doing it?
EDIT: I've re-adapted question, sorry
You might use overload to do the conversion at one place
static NTSTATUS Read(const void* p, size_t size, PVOID buff)
{
return Read(std::uintptr_t(p), size, buff);
}
You are using one int* since your function wait for uintptr_t.
One is signed, the other is unsigned.
Try to use unsigned instead of int or try to use std::intptr_t instead of std::uintptr_t
EDIT :
A way to solve your problem could be something like that :
class B {
int *number;
operator int*() {
return number;
}
};
After, you can do something like :
Read(*objA.second, ...);
The answer from Jarod42 can be good as well !
I suppose you could use a void pointer as an argument.For example:
static NTSTATUS Read(void* address, size_t size, PVOID buff);
But you should probably pass an other argument to the function in order to determine the type that you should cast the address variable to.So for example:
static NTSTATUS Read(void* address,unsigned code, size_t size, PVOID buff)
{
//code could be int=1,float=2,...
switch(code)
{
//handle each case int,float,custom type ...
//by casting the address to the corresponding type(code)
}
}
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.