I need to do the following C casting in Swift (4):
struct A ** castme = input
struct B * tothis = (struct B *)castme
In Swift, castme type is UnsafeMutablePointer<UnsafeMutablePointer<A>?>!
I assume I am trying to cast to UnsafeMutablePointer<B>! ?
Also, would it be correct to say that I could also cast *(castme) to a (struct B) directly? If yes, would it make casting easier by casting from UnsafeMutablePointer<A>? to B ?
I saw this thread but wasn't able to get what I needed from it:
Cast to different C struct unsafe pointer in Swift
Let's think about that in terms of what's happening in C. When I do a cast of pointers in C, the data that represents the pointer type will now be treated as a pointer of a different type. The value of the pointer doesn't change, just how you treat it.
Swift doesn't like to do this kind of thing and doesn't encourage you to do it because while cheap, it's a fundamentally unsafe thing to do and can lead to corrupting data, jumping into space, bus errors, etc.
That doesn't mean that swift doesn't have the ability to do this. The link that you point to uses withUnsafePointerTo which tries to limit the scope of the use of the pointer. In your case, you probably want to look at unsafeBitCast (documentation here) which mimics the C pointer cast (it's not strictly the same as C casting in general, but for pointers it is).
let a:UnsafeMutablePointer<SomeType> = fetchASomeTypePointer()
let b = unsafeBitCast(a, to: UnsafeMutablePointer<SomeOtherType>.self)
This makes the data representing the pointer to SomeType now become a pointer to SomeOtherType.
Like I said before, this is a dangerous thing to do especially if you don't fully understand what you're doing.
Related
I've seen many topics about typecasting integers into void * but I still have trouble understanding why it works without casting them, and why solving these warnings are so time-consuming, at least the way I see it.
I tried to make this topic as small as possible but trying to explain everything, but I think explaining the steps I did, how I was trying to do it, etc.. is much easier for people to understand my issue.
I'm working with linked lists and my structure is :
typedef struct list_t {
struct list_t *prev;
void *data;
struct list_t *next;
}list_s;
In the beginning, I simply set the data type as an integer, because I would always use integers in my program. My only problem was if I wanted to set the data value to NULL to check if there was something in my linked list (if I already used it once).
Some people would say "just set it to zero" but I could have a zero-value in my list, so there could be an error at some point.
I thought about just setting a variable such as "has_list_been_already_used" or something like that but I think that it would just make my code way bigger just for nothing.
My first thought after having this warning :
warning: assignment to ‘void *’ from ‘int’ makes pointer from integer without a cast
was: "oh I'll just cast it to void * like (void*)my_atoi(datastring); and that's it.
but I got another warning :
warning: cast to pointer from integer of different size
At this point, I didn't know what to do and didn't really find any issue to typecast this way. On the other hand, I've found another way of doing it, but I wonder if this is the right thing to do and if there is another way that doesn't lead to modifying almost all of my code and expanding it. Let me explain :
Someone said that you could just cast integers to void * this way :
int x = 10;
void *pointer = &x;
and retrieving it in the code such as :
int y = *((int *) pointer);
In my code, everywhere I would be retrieving my data from my structure, I will always have to do it this way.
Is that really the only option I got? And why just type-casting it from an integer to a void* doesn't do the job, especially if it "works well", but indeed, have warnings.
Thanks.
Typecasting pointer usually doesn't do anything internally. It however tells your compiler that is is to treat the pointer as a typed pointer.
So a pointer is literally that. It points to a place in memory. And what type of object is stored at that place is not always known. You can tell your compiler that it is an integer by casting: (int* iptr = (int*) voidptr)
Now your compiler will read the memory location pointed to by the pointer as if it was an integer. If it was not an integer, you will get garbled data.
Now this example:
int x = 10;
void *pointer = &x;
This is ok, because you say "make a pointer (to anything) form this pointer to an int" Which is ok, because a pointer to an int always points to anything.
But if you do it the other ways you have to explicitly say that you are sure there is an int stored there, because the compiler doesn't know.
If you want, you can just make a linkedlist of integers. Then you don't even need to use pointers. Just put the integer in the struct instead of the void*.
The reason this linkedlist structure is written this way, is that it allows for any type of data, or data structure to be used. This is why they added stuff like templating in c++. ( But we are talking c now)
The proper c way to do it would probably be to make a macro like
#define declare_LL_type(type) ...
Which would make a custom typed linkedlist struct definition.
Why do we have pointer types? eg
int *ptr;
I know its for type safety, eg to dereference 'ptr', the compiler needs to know that its dereferencing the ptr to type int, not to char or long, etc, but as others outlined here Why to specify a pointer type? , its also because "we should know how many bytes to read. Dereferencing a char pointer would imply taking one byte from memory while for int it could be 4 bytes." That makes sense.
But what if I have something like this:
typedef struct _IP_ADAPTER_INFO {
struct _IP_ADAPTER_INFO* Next;
DWORD ComboIndex;
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
UINT AddressLength;
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD Index;
UINT Type;
UINT DhcpEnabled;
PIP_ADDR_STRING CurrentIpAddress;
IP_ADDR_STRING IpAddressList;
IP_ADDR_STRING GatewayList;
IP_ADDR_STRING DhcpServer;
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer;
IP_ADDR_STRING SecondaryWinsServer;
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
What would be the point of declaring the type PIP_ADAPTER_INFO here? After all, unlike the previous example, we've already allocated enough memory for the pointer to point at (using malloc), so isn't defining the type here redundant? We will be reading as much data from memory as there has been allocated.
Also, side note: Is there any difference between the following 4 declarations or is there a best practice?
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
or
PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)malloc(sizeof(IP_ADAPTER_INFO));
or
IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
or
IP_ADAPTER_INFO *pAdapterInfo = (PIP_ADAPTER_INFO)malloc(sizeof(IP_ADAPTER_INFO));
You’re kind of asking two different questions here - why have different pointer types, and why hide pointers behind typedefs?
The primary reason for distinct pointer types comes from pointer arithmetic - if p points to an object of type T, then the expression p + 1 points to the next object of that type. If p points to an 4-byte int, then p + 1 points to the next int. If p points to a 128-byte struct, then p + 1 points to the next 128-byte struct, and so on. Pointers are abstractions of memory addresses with additional type semantics.
As for hiding pointers behind typedefs...
A number of us (including myself) consider hiding pointers behind typedefs to be bad style if the user of the type still has to be aware of the type’s “pointer-ness” (i.e., if you ever have to dereference it, or if you ever assign the result of malloc/calloc/realloc to it, etc.). If you’re trying to abstract away the “pointer-ness” of something, you need to do it in more than just the declaration - you need to provide a full API that hides all the pointer operations as well.
As for your last question, best practice in C is to not cast the result of malloc. Best practice in C++ is to not use malloc at all.
I think this is more a question of type definition style than of dynamic memory allocation.
Old-school C practice is to describe structs by their tags. You say
struct foo {
...
};
and then
struct foo foovar;
or
struct foo *foopointer = malloc(sizeof(struct foo));
But a lot of people don't like having to type that keyword struct all the time. (I guess I can't fault then; C has always favored terseness, sometimes seemingly just to reduce typing.) So a form using typedef became quite popular (and it either influenced, or was influenced by, C++):
typedef struct {
...
} Foo;
and then
Foo foovar;
or
Foo *foopointer = malloc(sizeof(Foo));
But then, for reasons that are less clear, it became popular to throw the pointerness into the typedef, too, like this:
typedef struct {
...
} Foo, *Foop;
Foop foopointer = malloc(sizeof(*Foop));
But this is all a matter of style and personal preference, in the service of what someone imagines to be clarity or convenience or usefulness. (But of course opinions on clarity and convenience, like opinions on style, can legitimately vary.) I've seen the pointer typedefs disparaged as being a misleading or Microsoftian practice, but I'm not sure I can fault them right now.
You also asked about the casts, and we could also dissect various options for the sizeof call as the argument to malloc.
It doesn't really matter whether you say
Foop foopointer = (Foop)malloc(sizeof(*Foop));
or
Foop foopointer = (Foo *)malloc(sizeof(*Foop));
The first one may be clearer, in that you don't have to go back and check that Foop and Foo * are the same thing. But they're both poor practice in C, and in at least some circles they've been deprecated since the 1990's. Those casts are are considered distracting and unnecessary in straight C -- although of course they're necessary in C++, or I suppose if you're using a C++ compiler to compile C code. (If you were writing straight C++ code, of course, you'd typically use new instead of malloc.)
But then what should you put in the sizeof()? Which is better,
Foop foopointer = malloc(sizeof(*Foop));
or
Foop foopointer = malloc(sizeof(Foo));
Again, the first one can be easier to read, since you don't have to go back and check that Foop and Foo * are the same thing. But by the same token, there's a third form that can be even clearer:
Foop foopointer = malloc(sizeof(*foopointer));
Now you know that, whatever type foopointer points at, you're allocating the right amount of space for it. This idiom works best, though, if it's maximally clear that foopiinter is in fact a pointer that points at some type, meaning that the variants
Foo *foopointer = malloc(sizeof(*foopointer));
or even
struct foo *foopointer = malloc(sizeof(*foopointer));
can be considered clearer still -- and this may be one of the reasons people consider the pointer typedef to be less than perfectly useful.
Bottom line, if you're still with me: If you don't find PIP_ADAPTER_INFO useful, don't use it -- use IP_ADAPTER_INFO (along with explicit *'s when you need them) instead. Someone thought PIP_ADAPTER_INFO might be useful, which is why it's there, but the arguments in favor of its use aren't too compelling.
What is the point of “pointer types” when you dynamically allocate memory?
At least for the example you show there is none.
So the follow up question would be if there were situations where typedefing a pointer made sense.
And the answer is: Yes.
It definitely makes sense if one is in the need of an opaque data type.
A nice example is the pthread_t type which defines a handle to a POSIX thread.
Depending on the implementation it is defined as
typedef struct bla pthread_t;
typedef struct foo * pthread_t;
typedef long pthread_t;
and with this abstracts away the kind of implementation, as it is of no interest to the user, which probably is not the intention with the struct you show in your question.
Why do we have pointer types?
To accommodate architectures where the size and encoding may differ for various types. C ports well to many platforms, even novel ones.
It is not unusual today that pointers to functions have a different size than pointers to objects. An object pointer coverts to a void *, yet a function pointer may not.
A pointer to char need not be the same size as a pointer to an int or union or struct. This is uncommon today. The spec details follow (my emphasis):
A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and alignment requirements
as each other. All pointers to union types shall have the same representation and
alignment requirements as each other. Pointers to other types need not have the same
representation or alignment requirements. C11dr §6.2.5 28
This question goes out to the C gurus out there:
In C, it is possible to declare a pointer as follows:
char (* p)[10];
.. which basically states that this pointer points to an array of 10 chars. The neat thing about declaring a pointer like this is that you will get a compile time error if you try to assign a pointer of an array of different size to p. It will also give you a compile time error if you try to assign the value of a simple char pointer to p. I tried this with gcc and it seems to work with ANSI, C89 and C99.
It looks to me like declaring a pointer like this would be very useful - particularly, when passing a pointer to a function. Usually, people would write the prototype of such a function like this:
void foo(char * p, int plen);
If you were expecting a buffer of an specific size, you would simply test the value of plen. However, you cannot be guaranteed that the person who passes p to you will really give you plen valid memory locations in that buffer. You have to trust that the person who called this function is doing the right thing. On the other hand:
void foo(char (*p)[10]);
..would force the caller to give you a buffer of the specified size.
This seems very useful but I have never seen a pointer declared like this in any code I have ever ran across.
My question is: Is there any reason why people do not declare pointers like this? Am I not seeing some obvious pitfall?
What you are saying in your post is absolutely correct. I'd say that every C developer comes to exactly the same discovery and to exactly the same conclusion when (if) they reach certain level of proficiency with C language.
When the specifics of your application area call for an array of specific fixed size (array size is a compile-time constant), the only proper way to pass such an array to a function is by using a pointer-to-array parameter
void foo(char (*p)[10]);
(in C++ language this is also done with references
void foo(char (&p)[10]);
).
This will enable language-level type checking, which will make sure that the array of exactly correct size is supplied as an argument. In fact, in many cases people use this technique implicitly, without even realizing it, hiding the array type behind a typedef name
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
Note additionally that the above code is invariant with relation to Vector3d type being an array or a struct. You can switch the definition of Vector3d at any time from an array to a struct and back, and you won't have to change the function declaration. In either case the functions will receive an aggregate object "by reference" (there are exceptions to this, but within the context of this discussion this is true).
However, you won't see this method of array passing used explicitly too often, simply because too many people get confused by a rather convoluted syntax and are simply not comfortable enough with such features of C language to use them properly. For this reason, in average real life, passing an array as a pointer to its first element is a more popular approach. It just looks "simpler".
But in reality, using the pointer to the first element for array passing is a very niche technique, a trick, which serves a very specific purpose: its one and only purpose is to facilitate passing arrays of different size (i.e. run-time size). If you really need to be able to process arrays of run-time size, then the proper way to pass such an array is by a pointer to its first element with the concrete size supplied by an additional parameter
void foo(char p[], unsigned plen);
Actually, in many cases it is very useful to be able to process arrays of run-time size, which also contributes to the popularity of the method. Many C developers simply never encounter (or never recognize) the need to process a fixed-size array, thus remaining oblivious to the proper fixed-size technique.
Nevertheless, if the array size is fixed, passing it as a pointer to an element
void foo(char p[])
is a major technique-level error, which unfortunately is rather widespread these days. A pointer-to-array technique is a much better approach in such cases.
Another reason that might hinder the adoption of the fixed-size array passing technique is the dominance of naive approach to typing of dynamically allocated arrays. For example, if the program calls for fixed arrays of type char[10] (as in your example), an average developer will malloc such arrays as
char *p = malloc(10 * sizeof *p);
This array cannot be passed to a function declared as
void foo(char (*p)[10]);
which confuses the average developer and makes them abandon the fixed-size parameter declaration without giving it a further thought. In reality though, the root of the problem lies in the naive malloc approach. The malloc format shown above should be reserved for arrays of run-time size. If the array type has compile-time size, a better way to malloc it would look as follows
char (*p)[10] = malloc(sizeof *p);
This, of course, can be easily passed to the above declared foo
foo(p);
and the compiler will perform the proper type checking. But again, this is overly confusing to an unprepared C developer, which is why you won't see it in too often in the "typical" average everyday code.
I would like to add to AndreyT's answer (in case anyone stumbles upon this page looking for more info on this topic):
As I begin to play more with these declarations, I realize that there is major handicap associated with them in C (apparently not in C++). It is fairly common to have a situation where you would like to give a caller a const pointer to a buffer you have written into. Unfortunately, this is not possible when declaring a pointer like this in C. In other words, the C standard (6.7.3 - Paragraph 8) is at odds with something like this:
int array[9];
const int (* p2)[9] = &array; /* Not legal unless array is const as well */
This constraint does not seem to be present in C++, making these type of declarations far more useful. But in the case of C, it is necessary to fall back to a regular pointer declaration whenever you want a const pointer to the fixed size buffer (unless the buffer itself was declared const to begin with). You can find more info in this mail thread: link text
This is a severe constraint in my opinion and it could be one of the main reasons why people do not usually declare pointers like this in C. The other being the fact that most people do not even know that you can declare a pointer like this as AndreyT has pointed out.
The obvious reason is that this code doesn't compile:
extern void foo(char (*p)[10]);
void bar() {
char p[10];
foo(p);
}
The default promotion of an array is to an unqualified pointer.
Also see this question, using foo(&p) should work.
I also want to use this syntax to enable more type checking.
But I also agree that the syntax and mental model of using pointers is simpler, and easier to remember.
Here are some more obstacles I have come across.
Accessing the array requires using (*p)[]:
void foo(char (*p)[10])
{
char c = (*p)[3];
(*p)[0] = 1;
}
It is tempting to use a local pointer-to-char instead:
void foo(char (*p)[10])
{
char *cp = (char *)p;
char c = cp[3];
cp[0] = 1;
}
But this would partially defeat the purpose of using the correct type.
One has to remember to use the address-of operator when assigning an array's address to a pointer-to-array:
char a[10];
char (*p)[10] = &a;
The address-of operator gets the address of the whole array in &a, with the correct type to assign it to p. Without the operator, a is automatically converted to the address of the first element of the array, same as in &a[0], which has a different type.
Since this automatic conversion is already taking place, I am always puzzled that the & is necessary. It is consistent with the use of & on variables of other types, but I have to remember that an array is special and that I need the & to get the correct type of address, even though the address value is the same.
One reason for my problem may be that I learned K&R C back in the 80s, which did not allow using the & operator on whole arrays yet (although some compilers ignored that or tolerated the syntax). Which, by the way, may be another reason why pointers-to-arrays have a hard time to get adopted: they only work properly since ANSI C, and the & operator limitation may have been another reason to deem them too awkward.
When typedef is not used to create a type for the pointer-to-array (in a common header file), then a global pointer-to-array needs a more complicated extern declaration to share it across files:
fileA:
char (*p)[10];
fileB:
extern char (*p)[10];
Well, simply put, C doesn't do things that way. An array of type T is passed around as a pointer to the first T in the array, and that's all you get.
This allows for some cool and elegant algorithms, such as looping through the array with expressions like
*dst++ = *src++
The downside is that management of the size is up to you. Unfortunately, failure to do this conscientiously has also led to millions of bugs in C coding, and/or opportunities for malevolent exploitation.
What comes close to what you ask in C is to pass around a struct (by value) or a pointer to one (by reference). As long as the same struct type is used on both sides of this operation, both the code that hand out the reference and the code that uses it are in agreement about the size of the data being handled.
Your struct can contain whatever data you want; it could contain your array of a well-defined size.
Still, nothing prevents you or an incompetent or malevolent coder from using casts to fool the compiler into treating your struct as one of a different size. The almost unshackled ability to do this kind of thing is a part of C's design.
You can declare an array of characters a number of ways:
char p[10];
char* p = (char*)malloc(10 * sizeof(char));
The prototype to a function that takes an array by value is:
void foo(char* p); //cannot modify p
or by reference:
void foo(char** p); //can modify p, derefernce by *p[0] = 'f';
or by array syntax:
void foo(char p[]); //same as char*
I would not recommend this solution
typedef int Vector3d[3];
since it obscures the fact that Vector3D has a type that you
must know about. Programmers usually dont expect variables of the
same type to have different sizes. Consider :
void foo(Vector3d a) {
Vector3d b;
}
where sizeof a != sizeof b
Maybe I'm missing something, but... since arrays are constant pointers, basically that means that there's no point in passing around pointers to them.
Couldn't you just use void foo(char p[10], int plen); ?
type (*)[];
// points to an array e.g
int (*ptr)[5];
// points to an 5 integer array
// gets the address of the array
type *[];
// points to an array of pointers e.g
int* ptr[5]
// point to an array of five integer pointers
// point to 5 adresses.
On my compiler (vs2008) it treats char (*p)[10] as an array of character pointers, as if there was no parentheses, even if I compile as a C file. Is compiler support for this "variable"? If so that is a major reason not to use it.
I know a pointer to one type may be converted to a pointer of another type. I have three questions:
What should kept in mind while typecasting pointers?
What are the exceptions/error may come in resulting pointer?
What are best practices to avoid exceptions/errors?
A program well written usually does not use much pointer typecasting. There could be a need to use ptr typecast for malloc for instance (declared (void *)malloc(...)), but it is not even necessary in C (while a few compilers may complain).
int *p = malloc(sizeof(int)); // no need of (int *)malloc(...)
However in system applications, sometimes you want to use a trick to perform binary or specific operation - and C, a language close to the machine structure, is convenient for that. For instance say you want to analyze the binary structure of a double (that follows thee IEEE 754 implementation), and working with binary elements is simpler, you may declare
typedef unsigned char byte;
double d = 0.9;
byte *p = (byte *)&d;
int i;
for (i=0 ; i<sizeof(double) ; i++) { ... work with b ... }
You may also use an union, this is an exemple.
A more complex utilisation could be the simulation of the C++ polymorphism, that requires to store the "classes" (structures) hierarchy somewhere to remember what is what, and perform pointer typecasting to have, for instance, a parent "class" pointer variable to point at some time to a derived class (see the C++ link also)
CRectangle rect;
CPolygon *p = (CPolygon *)▭
p->whatami = POLY_RECTANGLE; // a way to simulate polymorphism ...
process_poly ( p );
But in this case, maybe it's better to directly use C++!
Pointer typecast is to be used carefully for well determined situations that are part of the program analysis - before development starts.
Pointer typecast potential dangers
use them when it's not necessary - that is error prone and complexifies the program
pointing to an object of different size that may lead to an access overflow, wrong result...
pointer to two different structures like s1 *p = (s1 *)&s2; : relying on their size and alignment may lead to an error
(But to be fair, a skilled C programmer wouldn't commit the above mistakes...)
Best practice
use them only if you do need them, and comment the part well that explains why it is necessary
know what you are doing - again a skilled programmer may use tons of pointer typecasts without fail, i.e. don't try and see, it may work on such system / version / OS, and may not work on another one
In plain C you can cast any pointer type to any other pointer type. If you cast a pointer to or from an uncompatible type, and incorrectly write the memory, you may get a segmentation fault or unexpected results from your application.
Here is a sample code of casting structure pointers:
struct Entity {
int type;
}
struct DetailedEntity1 {
int type;
short val1;
}
struct DetailedEntity2 {
int type;
long val;
long val2;
}
// random code:
struct Entity* ent = (struct Entity*)ptr;
//bad:
struct DetailedEntity1* ent1 = (struct DetailedEntity1*)ent;
int a = ent->val; // may be an error here, invalid read
ent->val = 117; // possible invali write
//OK:
if (ent->type == DETAILED_ENTITY_1) {
((struct DetailedEntity1*)ent)->val1;
} else if (ent->type == DETAILED_ENTITY_2) {
((struct DetailedEntity2*)ent)->val2;
}
As for function pointers - you should always use functions which exactly fit the declaration. Otherwise you may get unexpected results or segfaults.
When casting from pointer to pointer (structure or not) you must ensure that the memory is aligned in the exact same way. When casting entire structures the best way to ensure it is to use the same order of the same variables at the start, and differentiating structures only after the "common header". Also remember, that memory alignment may differ from machine to machine, so you can't just send a struct pointer as a byte array and receive it as byte array. You may experience unexpected behaviour or even segfaults.
When casting smaller to larger variable pointers, you must be very careful. Consider this code:
char* ptr = malloc (16);
ptr++;
uint64_t* uintPtr = ptr; // may cause an error, memory is not properly aligned
And also, there is the strict aliasing rule that you should follow.
You probably need a look at ... the C-faq maintained by Steve Summit (which used to be posted in the newsgroups, which means it was read and updated by a lot of the best programmers at the time, sometimes the conceptors of the langage itself).
There is an abridged version too, which is maybe more palatable and still very, very, very, very useful. Reading the whole abridged is, I believe, mandatory if you use C.
I've come across some C code that I don't quite understand. The following compiles and runs just fine. 1) Why can I cast a char* to a struct* and 2) is there any advantage to using this idiom instead of a void* ?
struct foo
{
int a;
int b;
char *nextPtr;
};
. . .
// This seems wrong
char *charPtr = NULL;
// Why not
//void *structPtr = NULL;
struct foo *fooPtr;
fooPtr = (struct foo*)charPtr;
// Edit removing the string portion as that's not really the point of the question.
You can convert between pointer types because this is the flexibility the language gives you. However, you should be cautious and know what you are doing or problems are likely.
No. There is an advantage to using the property pointer type so that no conversion is needed. If that isn't possible, it doesn't really matter if you use void*, although it may be slightly more clear to developers reading your code.
1) As mentioned, you can cast to any pointer type in C. (C++ may have more complex rules, the details of which I'm not aware)...
2) The benefit of char* vs void* is that you may perform pointer arithmetic on a char* but not on a void*.
The wisdom in performing pointer arithmetic is probably questionable based on the code you've posted, but it's often handy with structures which have variable length 'data'.
I think you're just coming across one of those classic "double-edged swords" of C.
In reality, a pointer is a pointer - just a variable that holds an address. You could, in theory, try to force that pointer to point to anything; a struct, an int, a (fill in the blank). C won't complain when you try to cast a pointer to one thing to a pointer for something else; it figures you know what you're doing. Heaven help you if you don't :)
In reality, yeah, a void * is probably a more apt way to declare a pointer that could point to next to anything, but I'm not sure it makes much difference in operation. Won't swear to that point, as there might be compiler optimizations and such that can take place if the pointer is strongly typed...