473,322 Members | 1,566 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

FAQ 4.9 and void**

Hi

FAQ 4.9 states that void** cannot be used portably "to pass a generic
pointer to a function by reference". I would like to hear from you
whether there is anything wrong with the following approach when you
need a function to be able to modify a (void*) arg it has been passed:

struct pointer
{
void *p;
};

void fun(struct pointer *ptr)
{
ptr->p = NULL; /* assign whatever value you want to the (void*) we were
(indirectly) passed */
}

int main(void)
{
struct pointer ptr;

fun(&ptr);

return 0;
}

Is this a good way to do it? Or can I do it in a cleaner way?

Thank you,

MackS

Nov 14 '05 #1
6 1674


MackS wrote:
Hi

FAQ 4.9 states that void** cannot be used portably "to pass a generic
pointer to a function by reference". I would like to hear from you
whether there is anything wrong with the following approach when you
need a function to be able to modify a (void*) arg it has been passed:

struct pointer
{
void *p;
};

void fun(struct pointer *ptr)
{
ptr->p = NULL; /* assign whatever value you want to the (void*) we were
(indirectly) passed */
}

int main(void)
{
struct pointer ptr;

fun(&ptr);

return 0;
}

Is this a good way to do it? Or can I do it in a cleaner way?


Umh, usually you use void * for data where the type plays no role
or where you need a generic interface, e.g.

void fun1 (void *data, double param, double *pos)
{
int i;
double (*points)[2];

points = data;

for (i=0; i<2; i++)
pos[i] = (1.0-param)*points[0][i] + param*points[1][i];
}

void fun2 (void *data, double param, double *pos)
{
int i;
struct circle *circ;

circ = data;

pos[0] = circ->mp[0] + cos(2*PI*param)*circ->radius;
pos[1] = circ->mp[1] + sin(2*PI*param)*circ->radius;
}

.....

I am not sure whether this answers your question.
Maybe you can explain a little bit more what you want to achieve
or what application you have in mind where you would need to use
a void **.
Even a void ** can be passed as void *...
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #2
"MackS" <ma***********@hotmail.com> writes:
FAQ 4.9 states that void** cannot be used portably "to pass a generic
pointer to a function by reference". I would like to hear from you
whether there is anything wrong with the following approach when you
need a function to be able to modify a (void*) arg it has been passed:


You misunderstand the FAQ. You can use void ** to pass a void *
for initialization by a function. You can't use it, however, to
pass an int *, or a struct foo *, or a FILE *, for initialization
by a function. Your approach, of wrapping a void * in a struct,
is awkward and not likely to be of additional benefit. I could
see using a union, however, if you did want to initialize one out
of several types of pointers.
--
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Nov 14 '05 #3
MackS wrote:
Hi

FAQ 4.9 states that void** cannot be used portably "to pass a generic
pointer to a function by reference".
It is important to understand what exactly is meant by it. What the FAQ
is actually saying is that one can't portable do this

void foo(void** p) {
*p = /* something */;
}
int* p;
...
foo((void**) &p);

The above code attempts to do a raw low-level re-interpretation of
'int*' pointer as a 'void*' pointer. This will not work in general case.
That's what FAQ is saying.

However, the following will work just fine (assuming that 'foo' is
implemented correctly)

int* p;
void* vp;
...
vp = p; /* <- if necessary */
foo(&vp);
p = vp;

Note that in this case the code performs a language-level conversion of
'int*' value to 'void*' value (if necessary), invokes the function and
then performs the reverse conversion, again at language level. These
language-level pointer conversions is what preserves the portability of
the code (as opposed to raw memory re-interpretation in the previous
non-portable example).
I would like to hear from you
whether there is anything wrong with the following approach when you
need a function to be able to modify a (void*) arg it has been passed:

struct pointer
{
void *p;
};

void fun(struct pointer *ptr)
{
ptr->p = NULL; /* assign whatever value you want to the (void*) we were
(indirectly) passed */
}
...
Is this a good way to do it? Or can I do it in a cleaner way?
...


In essence this way is no different from the second (portable) example
above. Your approach can be misused in exactly the same way as the
'void**' one

int* p;
...
fun((struct pointer*) &p); /* Non-portable !!! */
...

However, I'd agree that from the point of view of pure "visual
readability", your approach seems to encourage the user to use the
proper technique more that the 'void**' variant. So it is up to you to
decide which variant is "better".

--
Best regards,
Andrey Tarasevich
Nov 14 '05 #4
Thank you all for your replies. My original post wasn't very clear.

Ben Pfaff wrote:

You can use void ** to pass a void * for initialization by a function.
You can't use it, however, to
pass an int *, or a struct foo *, or a FILE *, for initialization by a
function.

The latter is close to what I'm trying to do. Continuing with my
original example, assume I need fun() to be able to change the pointer
it is passed, and this pointer can be of several types -- eg, (int*) or
(struct foo*). So I tried to define the function as accepting a
(void**) argument. Consider the following case:

struct a {int i;};
struct b {int i;};

void fun(void **ptr)
{
*ptr = NULL;
return;
}

int main(void)
{
struct a p_a;
struct b p_b;

fun(p_a);

return 0;
}

This compiles succesfully but with the warning "passing arg 1 of 'fun'
from incompatible pointer type". My original post was an attempt at
understanding what might be going wrong with this code.

Looking at the example above, what is the optimal way to define fun()?

- should I ignore the warning?
- should I use a union? (Ben Pfaff)
- should I just "convert" the non-NULL pointer to a (void*) and then
pass its address as a (void**)?(Andrey Tarasevich)

Of the three, Andrey's suggestion of just adding an additional line
before the call to fun() in the code above

void *ptr = p_a;

and then calling

fun(&ptr);

seems like the cleanest way to do it. Is this valid, correct code?

Thank you for any help,

Mack

Nov 14 '05 #5
As must be clear, what I meant was

struct a *p_a;
struct b *p_b;

and not

struct a p_a;
struct b p_b;

Nov 14 '05 #6


MackS wrote:
Thank you all for your replies. My original post wasn't very clear.

Ben Pfaff wrote:

You can use void ** to pass a void * for initialization by a function.
You can't use it, however, to
pass an int *, or a struct foo *, or a FILE *, for initialization by a
function.

The latter is close to what I'm trying to do. Continuing with my
original example, assume I need fun() to be able to change the pointer
it is passed, and this pointer can be of several types -- eg, (int*) or
(struct foo*). So I tried to define the function as accepting a
(void**) argument. Consider the following case:

struct a {int i;};
struct b {int i;};

void fun(void **ptr)
{
*ptr = NULL;
return;
}

int main(void)
{
struct a p_a;
struct b p_b;

fun(p_a);

return 0;
}

This compiles succesfully
Complain to the compiler vendor. fun() expects to
recieve a `void**' argument, but is being given a `struct a'
argument instead. `struct a' is not convertible to `void**',
not even by casting.

Are you sure this is the actual code? I'll bet you
forty-two dozen Krispy Kreme doughnuts and a cholesterol
screening that it's a messed-up paraphrase. In what follows,
I'll assume you actually had

struct a * p_a;
...
fun(&p_a);

.... and if my assumption is wrong you have only yourself to
blame. Next time, cut and paste.
but with the warning "passing arg 1 of 'fun'
from incompatible pointer type". My original post was an attempt at
understanding what might be going wrong with this code.

Looking at the example above, what is the optimal way to define fun()?

- should I ignore the warning?
Yes, if you don't mind taking chances. The code (as
reconstructed) is not portable; it may work on some systems
while failing in mysterious ways on others. If your intent
is to write programs that resemble houses of cards ...
- should I use a union? (Ben Pfaff)
You'd need some way to tell fun() which of the union's
members it should set.
- should I just "convert" the non-NULL pointer to a (void*) and then
pass its address as a (void**)?(Andrey Tarasevich)
That would work.
Of the three, Andrey's suggestion of just adding an additional line
before the call to fun() in the code above

void *ptr = p_a;

and then calling

fun(&ptr);

seems like the cleanest way to do it. Is this valid, correct code?


Yes. Valid, correct -- and probably pointless. If fun()
is to do anything "useful" with the targetted pointer (e.g.,
allocate some memory for it), it usually needs to know something
about the type of the pointed-to object (e.g., how big it is).
The two "usual" ways to handle this are (1) to write fun() so
it accepts a `KnownType**' instead of a `void**', or (2) to
have fun() return a `void*' that the caller can then assign to
a `KnownType*' variable.

There's an important and vexing situation where (1) and (2)
don't quite suffice, and that's in writing functions to operate
on user-defined linked structures: sorting a linked list, say,
or traversing a binary tree. This requires that fun() be able
to manipulate pointers of unknown type, and C isn't good at that.
However, there's an escape clause that usually handles this sort
of thing: Although C pointers to different object types may have
different representations, all pointers to all struct types have
the same representation. On the likely assumption that the nodes
in the linked list or binary tree are structs of some kind, you
can have fun() work on `struct unknown*' pointers with reasonable
safety.

Turning back to why things are the way they are, here's an
analogy that may help you appreciate the difficulty. It seems
to you that fun() should manipulate "pointers," and you seek a
way to point to a pointer variable without worrying about the
variable's type. Now consider writing a fun2() that takes as
an argument a pointer to a number

void fun2( SomeNumberType *ptr ) {
*ptr = 42;
}

.... and the question is how to write "SomeNumberType" so that
fun2() will work correctly in all of these calls:

short s;
int i;
size_t z;
double d;
unsigned char uc;
...
fun2(&s);
fun2(&i);
fun2(&z);
fun2(&d);
fun2(&uc);

Most people seem able to appreciate that this isn't going to
work; even though all the pointed-to variables are "numbers"
they have different sizes and represent forty-two differently.
The lone assignment inside fun2() cannot cope with all the
different format possibilities simultaneously. The case is
similar with variables that are pointers to different types:
they are all "pointers," but they may have different sizes
and represent their values differently. The single assignment
in fun() cannot deal with all pointer types simultaneously.

--
Er*********@sun.com

Nov 14 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

192
by: Kwan Ting | last post by:
The_Sage, I see you've gotten yourself a twin asking for program in comp.lang.c++ . http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&th=45cd1b289c71c33c&rnum=1 If you the oh so mighty...
15
by: Stig Brautaset | last post by:
Hi group, I'm playing with a little generic linked list/stack library, and have a little problem with the interface of the pop() function. If I used a struct like this it would be simple: ...
188
by: infobahn | last post by:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
7
by: sunglo | last post by:
My doubt comes from trying to understand how thread return values work (I know, it's off topic here), and I'm wondering about the meaning of the "void **" parameter that pthread_join expects (I...
9
by: Juggernaut | last post by:
I am trying to create a p_thread pthread_create(&threads, &attr, Teste, (void *)var); where var is a char variable. But this doesnt't work, I get this message: test.c:58: warning: cast to pointer...
5
by: Stijn van Dongen | last post by:
A question about void*. I have a hash library where the hash create function accepts functions unsigned (*hash)(const void *a) int (*cmp) (const void *a, const void *b) The insert function...
56
by: maadhuu | last post by:
hello, this is a piece of code ,which is giving an error. #include<stdio.h> int main() { int a =10; void *p = &a; printf("%d ", *p ); //error....why should it //be an error ?can't the...
27
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in...
18
by: Giannis Papadopoulos | last post by:
According to the standard (ISO C99 draft WG14/N1124), void is the incomplete type that cannot be completed and comprises the empty set of values. Since it declares the absense of a value can it be...
4
by: brianhray | last post by:
Hello: I am writing a C interface and was curious how/why a void* can be used as a reference parameter. //////////////////////////////////////////////////////////// // WORKS: // Client1.h...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.