Given these typedefs and the value below:
typedef void GTVOID;
typedef GTVOID *PARAM_VALUE;
typedef unsigned long UDGT32
typedef UDGT32 PARAM_CONST;
typedef signed long DGT32;
typedef DGT32 RESULT_FUNC;
DWORD value = 1; // given from a define
How I can convert it to satisfy the needs of that device SDK function in C++?
RESULT_FUN RSetParam( PARAM_CONST DeviceParameter, PARAM_VALUE value);
The C reference code in samples is:
RSetParam( R_SOME_PARAM_CONST, (PARAM_VALUE)value );
I tried it below, but it's just weird. It compiles ok, works all day long and by some
creepy luck, starts throwing access violations out of blue:
RSetParam(R_SOME_PARAM_CONST, reinterpret_cast<void*> (value));
What I'm doing wrong?
You have tried to reinterpret the value 1 as an address. Depending on what the function RSetParam is doing with this address (value), the program may seg-fault. Especially, if it tries to write to this address.
I think, the function RSetParam awaits an address to a variable as second argument. The type of the variable might depend on something else, that is, why the adress must be passed as void *.
So, if you want to pass number 1 as DWORD you have to allocate a variable on the stack first and then pass its address:
DWORD tmp = 1; // given from define
RSetParam( R_SOME_PARAM_CONST, (PARAM_VALUE) &tmp ); // note the '&' !
Related
I am learning C++ using C++ Primer 5th edition. In particular, i read about void*. There it is written that:
We cannot use a void* to operate on the object it addresses—we don’t know that object’s type, and the type determines what operations we can perform on that object.
void*: Pointer type that can point to any nonconst type. Such pointers may not
be dereferenced.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*. Also, i am not sure if the above quoted statement from C++ Primer is technically correct because i am not able to understand what it is conveying. Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses". So can someone please provide some example to clarify what the author meant and whether he is correct or incorrect in saying the above statement.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*
It's indeed quite rare to need void* in C++. It's more common in C.
But where it's useful is type-erasure. For example, try to store an object of any type in a variable, determining the type at runtime. You'll find that hiding the type becomes essential to achieve that task.
What you may be missing is that it is possible to convert the void* back to the typed pointer afterwards (or in special cases, you can reinterpret as another pointer type), which allows you to operate on the object.
Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses"
Example:
int i;
int* int_ptr = &i;
void* void_ptr = &i;
*int_ptr = 42; // OK
*void_ptr = 42; // ill-formed
As the example demonstrates, we cannot modify the pointed int object through the pointer to void.
so since a void* has no size(as written in the answer by PMF)
Their answer is misleading or you've misunderstood. The pointer has a size. But since there is no information about the type of the pointed object, the size of the pointed object is unknown. In a way, that's part of why it can point to an object of any size.
so how can a int* on the right hand side be implicitly converted to a void*
All pointers to objects can implicitly be converted to void* because the language rules say so.
Yes, the author is right.
A pointer of type void* cannot be dereferenced, because it has no size1. The compiler would not know how much data he needs to get from that address if you try to access it:
void* myData = std::malloc(1000); // Allocate some memory (note that the return type of malloc() is void*)
int value = *myData; // Error, can't dereference
int field = myData->myField; // Error, a void pointer obviously has no fields
The first example fails because the compiler doesn't know how much data to get. We need to tell it the size of the data to get:
int value = *(int*)myData; // Now fine, we have casted the pointer to int*
int value = *(char*)myData; // Fine too, but NOT the same as above!
or, to be more in the C++-world:
int value = *static_cast<int*>(myData);
int value = *static_cast<char*>(myData);
The two examples return a different result, because the first gets an integer (32 bit on most systems) from the target address, while the second only gets a single byte and then moves that to a larger variable.
The reason why the use of void* is sometimes still useful is when the type of data doesn't matter much, like when just copying stuff around. Methods such as memset or memcpy take void* parameters, since they don't care about the actual structure of the data (but they need to be given the size explicitly). When working in C++ (as opposed to C) you'll not use these very often, though.
1 "No size" applies to the size of the destination object, not the size of the variable containing the pointer. sizeof(void*) is perfectly valid and returns, the size of a pointer variable. This is always equal to any other pointer size, so sizeof(void*)==sizeof(int*)==sizeof(MyClass*) is always true (for 99% of today's compilers at least). The type of the pointer however defines the size of the element it points to. And that is required for the compiler so he knows how much data he needs to get, or, when used with + or -, how much to add or subtract to get the address of the next or previous elements.
void * is basically a catch-all type. Any pointer type can be implicitly cast to void * without getting any errors. As such, it is mostly used in low level data manipulations, where all that matters is the data that some memory block contains, rather than what the data represents. On the flip side, when you have a void * pointer, it is impossible to determine directly which type it was originally. That's why you can't operate on the object it addresses.
if we try something like
typedef struct foo {
int key;
int value;
} t_foo;
void try_fill_with_zero(void *destination) {
destination->key = 0;
destination->value = 0;
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
try_fill_with_zero(foo_instance, sizeof(t_foo));
}
we will get a compilation error because it is impossible to determine what type void *destination was, as soon as the address gets into try_fill_with_zero. That's an example of being unable to "use a void* to operate on the object it addresses"
Typically you will see something like this:
typedef struct foo {
int key;
int value;
} t_foo;
void init_with_zero(void *destination, size_t bytes) {
unsigned char *to_fill = (unsigned char *)destination;
for (int i = 0; i < bytes; i++) {
to_fill[i] = 0;
}
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
int test_int;
init_with_zero(foo_instance, sizeof(t_foo));
init_with_zero(&test_int, sizeof(int));
}
Here we can operate on the memory that we pass to init_with_zero represented as bytes.
You can think of void * as representing missing knowledge about the associated type of the data at this address. You may still cast it to something else and then dereference it, if you know what is behind it. Example:
int n = 5;
void * p = (void *) &n;
At this point, p we have lost the type information for p and thus, the compiler does not know what to do with it. But if you know this p is an address to an integer, then you can use that information:
int * q = (int *) p;
int m = *q;
And m will be equal to n.
void is not a type like any other. There is no object of type void. Hence, there exists no way of operating on such pointers.
This is one of my favourite kind of questions because at first I was also so confused about void pointers.
Like the rest of the Answers above void * refers to a generic type of data.
Being a void pointer you must understand that it only holds the address of some kind of data or object.
No other information about the object itself, at first you are asking yourself why do you even need this if it's only able to hold an address. That's because you can still cast your pointer to a more specific kind of data, and that's the real power.
Making generic functions that works with all kind of data.
And to be more clear let's say you want to implement generic sorting algorithm.
The sorting algorithm has basically 2 steps:
The algorithm itself.
The comparation between the objects.
Here we will also talk about pointer functions.
Let's take for example qsort built in function
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
We see that it takes the next parameters:
base − This is the pointer to the first element of the array to be sorted.
nitems − This is the number of elements in the array pointed by base.
size − This is the size in bytes of each element in the array.
compar − This is the function that compares two elements.
And based on the article that I referenced above we can do something like this:
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
int main () {
int n;
printf("Before sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
return(0);
}
Where you can define your own custom compare function that can match any kind of data, there can be even a more complex data structure like a class instance of some kind of object you just define. Let's say a Person class, that has a field age and you want to sort all Persons by age.
And that's one example where you can use void * , you can abstract this and create other use cases based on this example.
It is true that is a C example, but I think, being something that appeared in C can make more sense of the real usage of void *. If you can understand what you can do with void * you are good to go.
For C++ you can also check templates, templates can let you achieve a generic type for your functions / objects.
I am working on Student Project and got SDK from site and building libraries on Visual Studio. Once I build libraries using cmake opened solution in VS and build in VS gives me above error. Not sure how to fix it.
This is proc where I get error.
pmdDllExport int pmdpGetSourceDataDescription (unsigned hnd, PMDDataDescription *result)
{
if (!idOk (hnd))
{
globalErrorMessage = "unknown handle";
return PMD_UNKNOWN_HANDLE;
}
SrcPluginData *dat = g_data[hnd];
int c_channels = 1;
//
dat->currentDD.type = PMD_USER_DEFINED_0; /* USER DEFINE TYPE DATA for O3D3xx data*/
dat->currentDD.subHeaderType = PMD_IMAGE_DATA;
dat->currentDD.img.numSubImages = 6;/* Mentions number of images in image data
buffer. We have six images*/
...
/* Get Size of image data buffer */
**dat->o3d3xxCamera->getFrameDataSize (& (dat->currentDD.size));**
dat->currentDD.PID = hnd;
dat->currentDD.DID = g_did;
/*Output this descriptor to calling function */
memcpy (result , &dat->currentDD, sizeof (PMDDataDescription));
return PMD_OK;
}
When I checked what is o3d3xxCamera->getFrameDataSize defined as it is defined as
int32_t getFrameDataSize (size_t *dataSize);
I looked at many queries and they say better to pass variable as type size_t When I checked what is dat->currentdd its struct. So I am not sure how to change this type to size_t.
/**<local datadescriptor of the current data */
PMDDataDescription currentDD;
struct PMDDataDescription
{
unsigned PID;
unsigned DID;
unsigned type;
unsigned size;
unsigned subHeaderType;
...
Do not be tempted to just reintepret_cast the pointer! That will not do what you want, unless size_t happens to be the same as unsigned int, which varies from platform to platform.
Instead, you'll want to use a temporary, and copy back when you're done:
size_t size = dat->currentDD.size; // this will promote as necessary
dat->o3d3xxCamera->getFrameDataSize(&size);
dat->currentDD.size = size; // write it back
One or other of the assignments may need a static_cast, if sizeof (size_t) differs from sizeof (unsigned int). This is fine, as it will be value-preserving (assuming that the value is representable in both types).
If the types have different sizes, you can't reliably cast!
The receiver will treat the pointer as a pointer to a variable with a different size from what you actually have, and there will be breakage (undefined behavior).
Simply change the structure to have
size_t size;
If you can't change the structure, then of course you can use a temporary for the call, then cast that value into the struct. That will work, assuming you never need the higher precision of size_t of course.
dat->o3d3xxCamera->getFrameDataSize (& (dat->currentDD.size));
This passes the address of dat->currentDD.size as parameter to the getFrameDataSize() function.
PMDDataDescription currentDD;
struct PMDDataDescription
{
unsigned PID;
unsigned DID;
unsigned type;
unsigned size;
currentDD.size is of type unsigned.
int32_t getFrameDataSize (size_t *dataSize);
The function expects the addess of a size_t.
Cannot convert argument 1 from " unsigned int *" to "size t *"
Apparently on your system size_t is typedef'ed to something different than unsigned int, making the two pointers incompatible. This might happen on 64-bit systems, where int is 32bit, but size_t is 64bit.
The easy fix is to simply cast the type (1):
dat->o3d3xxCamera->getFrameDataSize(& ( static_cast< size_t >(dat->currentDD.size) ) );
The Right Thing (tm) would probably (2) be to refactor PMDDataDescription to use size_t for its size member.
(1): I say it's easy, not that it's correct. I have no idea what PMDDataDescription is, what library it might come from, or what it is used for. I do not know what getFrameDataSize() does with its parameter. If it does pointer arithmetics on it, casting will break your application, and there is virtually nothing you can do about it because the two API's involved apparently to not agree on data types. We're looking at a very fragile setup here.
(2): You might not have control over its sources. You might be looking at something that is part of a specified API, i.e. cannot be changed for practical reasons. I'm just sayin' that properly constructed software shouldn't have run into this problem in the first place.
You cannot cast pointers. You should try instead to cast only 'unsigned char' into 'size_t', not 'unsigned char*' and 'size_t*'
I am getting quite confused alot about pointers in structures.
I have a piece of code which i do no understand fully yet,
the code:
typedef struct{
int fildes // basic file descriptor
char* location // location would be somewhere in /dev/tty*
}context0; // structure named 'context' containing the 2 elements above.
context0 someContext; // create a context struct
process(&readLocation); // takes reference from the function 'readlocation'
// i do not know what this process function does.
uint_16_t readLocation(int8_t *buffer, int16_t n, SomeContext){ // buffer pointer, n size read, and fidles
context0 foo = *(context0*) SomeContext; // ???? What Is Going ON right here ????
return read(foo.fd, buffer, n);
}
I have changed some of the names but its the code which i do not fully understand.
Some questions:
since readLocation function is passed as a reference should it not be defined as void* ? infront of the uint_32_t
main question: what does the context0 foo = * (context0*) SomeContext; do?
ok so it seems that (context0 *) is infact a typecast which is done by (int)bar to set some other type to the type of 'int'. this is done to set the variable bar to the type of context.
this typecast can also be done to a pointer type cast wich would be done as (int*) or (struct name*), or in this case (context0 *).
lastly the pointer outside of the parenthisis dereferences the structure pointer to acces whatever it points towards and places this information in the struct context0 foo.
why this is nessesary i do not know but the syntax points to this.
thanks, oh ur welcome np
and thank u Gábor Angyal, but cannot give points or whatever level 1
How would someone get the actual location/address of result function 1002DDCC3 through offset in IDA PRO?
Specifically the "a1 + 0x2E0" part.
It calls a new function obviously sub_100xxxxx;
Let's say
a1 == 942691698;
int (__stdcall *__stdcall QueryInterface(unsigned int a1))(int)
{
if ( a1 == 942691698 )
return (int (__stdcall *)(int))sub_1002DDC3;
}
int __stdcall sub_1002DDC3(int a1, int a2)
{
int result; // eax#2
if ( a1 )
result = (*(int (__stdcall **)(_DWORD))(*(_DWORD *)a1 + 0x2E0))(a2);
else
result = -1;
return result;
}
Raw Assembly of the function 1002DDC3 is http://img.techpowerup.org/121010/Capture.png
Your wording is very unclear. Assuming that QueryInterface() really does have something to do with IUnknown::QueryInterface():
If you're asking "what is the meaning of the return value of sub_1002DDC3()", it's probably an HRESULT. The most important values here are zero (S_OK), -1 (general error), and non-zero (specific errors).
Or are you asking "what is the address of sub_1002DDC3()?"
It would actually be easier to understand this if you could post the raw disassembly.
Edited to add
The address of the interface method is determined at runtime. The disassembler doesn't know the addresses in advance and so can't tell you which method is being called.
Yes, you need to disassemble the COM object separately.
It depends on the value of the 'a1' argument. Since this function can be called with different values of 'a1', it is impossible to tell by just looking at the listing. You will have to run it under a debugger or check the callers.
I do not understand why the pointer addition is failing.
DWORD *pipebuf=new DWORD[10001];
Command *cr= (Command*)pipebuf;
cr->command=2;
DWORD* rooms=(pipebuf+1); //should work fine..sets the room pointer equal to pipe[2]
*rooms=buff3; //where buff3=100
Yet, the value of pipebuf only contains the value of command, it does not contain the value of buff3. Yet, when I remove the new keyword it works fine...Why?
DWORD=unsigned_int
Command is a class with a DWORD variable of command.. something like this
Class Command {
DWORD command;
}
The addition moves the pointer forward one, causing it to point at the second DWORD in your array. *(pipebuf+1) is precisely equivalent to pipebuf[1]; after your code runs, *pipebuf aka pipebuf[0] aka cr->command is equal to 2, while *(pipebuf+1) aka *rooms aka pipebuf[1] is equal to 100.
Note however that typecasting between pointer types in C++ is often considered bad style and can in many circumstances have undesirable results. If you are allocating an array of Command's, then use new Command[...]; if you want DWORD's, then don't cast into Command*.
Sometimes you have to cast pointers between types, but generally you should only do that if you know exactly what you're doing and why you can't avoid doing so.
Furthermore, if you do need to, you should either be using static_cast (in cases like this) or dynamic_cast (in cases where the types are related by inheritance; this usage is much safer generally).
class Command is a user defined type and DWORD is a primitive data type ( unsigned int ). In that case, why doing this -
Command *cr= (Command*)pipebuf;
class Command {
public : // Added public keyword
DWORD command; // DWORD is a typedef for unsigned int as you mentioned.
}; // class definition should end with a semi-colon
So, this is the way to do -
Command *cr = new Command[10001] ;
DWORD *pipebuf=new DWORD[10001];
// After assigining values to DWORD pointed locations. Then you can do this -
cr->command = pipebuf[0] ; // this sets the value of cr[0].command.
I'd make this a comment, but I can't do code formatting in those.
I ran this code, and the output is "2 100" as expected:
#include <iostream>
using namespace std;
typedef unsigned int DWORD;
class Command {
public:
DWORD command;
};
int main()
{
DWORD buff3 = 100;
DWORD *pipebuf = new DWORD[10001];
Command *cr = (Command*)pipebuf;
cr->command = 2;
DWORD *rooms = (pipebuf+1);
*rooms = buff3;
std::cout << pipebuf[0] << " " << pipebuf[1] << endl;
}
AFAICT that's the simplest way you could expand your question into a complete program.
Could you try taking this and adding more stuff from the original code until you get the problem to appear?