473,386 Members | 1,810 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,386 software developers and data experts.

Confused about "void **"

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 think this is
topical, since it's a C question, but please correct me and apologies
if I'm wrong).

I suppose that it's this way to allow for "generic" pointer
modification, but this implies dereferencing the "void **" pointer to
get a "void *" one. So, is this allowed or does the implementation have
to play some trick somewhere, like for example casting the void ** to
another type (for example, int ** on a 32 bit machine) that can then be
safely dereferenced?

Thanks

Nov 14 '05 #1
7 2450
REH

<su****@katamail.com> wrote in message
news:11**********************@l41g2000cwc.googlegr oups.com...
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 think this is
topical, since it's a C question, but please correct me and apologies
if I'm wrong).

I suppose that it's this way to allow for "generic" pointer
modification, but this implies dereferencing the "void **" pointer to
get a "void *" one. So, is this allowed or does the implementation have
to play some trick somewhere, like for example casting the void ** to
another type (for example, int ** on a 32 bit machine) that can then be
safely dereferenced?

Thanks


The function is expecting you to give it a pointer to void that it is going
to set to something. If a function takes an object of type T that it must
modify for the caller, it must be given a pointer to the object, thus T*.
The function wants to modify a void*, so if T is void*, then T* is void**

I hope that was clear enough.

REH
Nov 14 '05 #2


su****@katamail.com wrote:
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 think this is
topical, since it's a C question, but please correct me and apologies
if I'm wrong).

I suppose that it's this way to allow for "generic" pointer
modification, but this implies dereferencing the "void **" pointer to
get a "void *" one. So, is this allowed or does the implementation have
to play some trick somewhere, like for example casting the void ** to
another type (for example, int ** on a 32 bit machine) that can then be
safely dereferenced?


No tricks. You cannot dereference a `void*' because
it points to what's called an "incomplete type" -- loosely
speaking, it points to the start of a piece of anonymous
memory of unknown size and significance. You know where
the memory is, but you don't know how big it is or how to
interpret its contents -- in short, you don't know how to
"refer" to it.

However, a `void*' itself is a perfectly normal data
object, just like an `int' or a `double*'. Its size is
known and its representation is known, so if you know that
a certain piece of memory holds a `void*' you have enough
information to fetch or store a `void*' value in that memory.
And what kind of a pointer points to a `void*'? A `void**',
of course. There's no trickery about it.

However, this doesn't mean a `void**' is a "generic
pointer to pointer" in the sense that `void*' is frequently
called a "generic pointer." A `void*' can point to any kind
of data object (because it will not be dereferenced), but
a `void**' can only properly point to a `void*' -- it can't
point to an `int*' or a `double*'. (There's a special rule
that allows it to point to a `char*', but that rule exists
only to legitimize pre-Standard code, and is best ignored.)

What this means (we're straying near the frontiers of
topicality here, but your question is a bona-fide C question
even though it involves beyond-C API's) is that

- Your thread function creates a data object containing
its Final Answer (taking care to use an object that
will survive the thread's demise), takes a pointer
to that object and converts it to `void*' (the
conversion is automatic, but it occurs), and returns
that `void*' value.

- The thread_join() function locates the `void*' value
returned by the defunct thread, and wants to put it
somewhere for your inspection. To receive the value,
you create a `void*' variable somewhere and pass a
pointer to it -- a `void**' -- to thread_join(), which
plunks the value in the place you indicate.

- Now you've got the `void*' that the thread returned,
but you can't do much with it because you can't
dereference it. However, you know the type of the
data object that holds the thread's Final Answer, so
you can convert the `void*' to a pointer to that data
type (again, the conversion is automatic), and with
that pointer you can access to the thread's Last Will
and Testament.

Pseudocode outline:

struct final_answer { int this; double that; };
...
void *thread(...) {
struct final_answer *adios = malloc(sizeof *adios);
...
adios->this = 42;
adios->that = 12e34;
return adios;
}
...
void *raw_result;
struct final_answer *result;
thread_join(..., &raw_result);
/* This ^^^^^^^^^^^ is the `void**' */
result = raw_result;
printf ("%d, %g\n", result->this, result->that);

The `raw_result' variable is necessary here; you cannot
just pass `&result' as the thread_join() argument.

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

Nov 14 '05 #3

Eric Sosman wrote:
No tricks. You cannot dereference a `void*' because
it points to what's called an "incomplete type" -- loosely
speaking, it points to the start of a piece of anonymous
memory of unknown size and significance. You know where
the memory is, but you don't know how big it is or how to
interpret its contents -- in short, you don't know how to
"refer" to it.
[cut]
Great, a lot more than what I asked! Thanks.
Pseudocode outline:

struct final_answer { int this; double that; };
...
void *thread(...) {
struct final_answer *adios = malloc(sizeof *adios);
...
adios->this = 42;
adios->that = 12e34;
return adios;
}
...
void *raw_result;
struct final_answer *result;
thread_join(..., &raw_result);
/* This ^^^^^^^^^^^ is the `void**' */
result = raw_result;
printf ("%d, %g\n", result->this, result->that);

The `raw_result' variable is necessary here; you cannot
just pass `&result' as the thread_join() argument.


I have a feeling that passing (void **)&result instead is not strictly
correct (although it might work), but I can't exactly figure out
why...can you help me with this too?

Thanks

Nov 14 '05 #4
su****@katamail.com wrote:
...
Pseudocode outline:

struct final_answer { int this; double that; };
...
void *thread(...) {
struct final_answer *adios = malloc(sizeof *adios);
...
adios->this = 42;
adios->that = 12e34;
return adios;
}
...
void *raw_result;
struct final_answer *result;
thread_join(..., &raw_result);
/* This ^^^^^^^^^^^ is the `void**' */
result = raw_result;
printf ("%d, %g\n", result->this, result->that);

The `raw_result' variable is necessary here; you cannot
just pass `&result' as the thread_join() argument.


I have a feeling that passing (void **)&result instead is not strictly
correct (although it might work), but I can't exactly figure out
why...can you help me with this too?


http://groups-beta.google.com/group/...37a6ee610f1317

--
Best regards,
Andrey Tarasevich
Nov 14 '05 #5


su****@katamail.com wrote:
Eric Sosman wrote:
...
void *raw_result;
struct final_answer *result;
thread_join(..., &raw_result);
/* This ^^^^^^^^^^^ is the `void**' */
result = raw_result;
printf ("%d, %g\n", result->this, result->that);

The `raw_result' variable is necessary here; you cannot
just pass `&result' as the thread_join() argument.


I have a feeling that passing (void **)&result instead is not strictly
correct (although it might work), but I can't exactly figure out
why...can you help me with this too?


It would be incorrect, for the same reason that

int *ptr;
double val = strtod("123.45%", (char**)&ptr);

is incorrect. strtod() wants to store a value into a
`char*' variable, and giving it an `int*' (even if
disguised) is asking for trouble. thread_join() wants
to store a value into a `void*', and giving it a
`struct final_answer*' (even if disguised) is asking
for trouble.

"A rose is a rose is a rose," but it does not follow
that "a pointer is a pointer is a pointer." Pointers
need not all have the same size, nor need they all assign
the same meaning to each bit of their representations;
pointers of different types are not interchangeable
except in a few special cases (of which this is not one).
An `int' and a `double' can occupy different amounts of
memory and have different bit patterns even though they
both represent the value forty-two; just so, a `void*'
and a `struct final_answer*' can occupy different amounts
of memory and have different bit patterns even though they
both point to the same data object.

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

Nov 14 '05 #6

Eric Sosman wrote:
"A rose is a rose is a rose," but it does not follow
that "a pointer is a pointer is a pointer." Pointers
need not all have the same size, nor need they all assign
the same meaning to each bit of their representations;
pointers of different types are not interchangeable
except in a few special cases (of which this is not one).
An `int' and a `double' can occupy different amounts of
memory and have different bit patterns even though they
both represent the value forty-two; just so, a `void*'
and a `struct final_answer*' can occupy different amounts
of memory and have different bit patterns even though they
both point to the same data object.


You are absolutely correct. The point is, if someone (like me)
always works on machines where pointers happen to have all
the same size and representation, which happen to be the same
size and representation of ints, the above problems are not
always taken into consideration. Nonetheless, they are real
and must be considered when portability is needed.

Thanks again to you and all the others who replied.

Nov 14 '05 #7
su****@katamail.com writes:
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 think this is
topical, since it's a C question, but please correct me and apologies
if I'm wrong).

I suppose that it's this way to allow for "generic" pointer
modification, but this implies dereferencing the "void **" pointer to
get a "void *" one. So, is this allowed or does the implementation have
to play some trick somewhere, like for example casting the void ** to
another type (for example, int ** on a 32 bit machine) that can then be
safely dereferenced?


A quick summary:

A void* is a generic pointer.

A void** is not a generic pointer-to-pointer (C has no such thing);
it's a pointer-to-generic-pointer.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #8

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

Similar topics

7
by: Ollej Reemt | last post by:
Hello, I would like to know if there is a difference in c++ between the following two method-declarations: void Method(); and void Method(void);
188
by: infobahn | last post by:
printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
1
by: Benny Ng | last post by:
Hi,All, Export Method: ------------------------------------------------------------------------- strFileNameExport = "Results" Response.Clear() Response.Buffer = True...
3
by: sandy | last post by:
I cannot figure this out. I have the following code: <code> Private: /****************************************************************************** CreateList
1
by: hpandey | last post by:
sigaction : using "void (*sa_sigaction)(int, siginfo_t *, void *);" -------------------------------------------------------------------------------- hello, in sigaction manpage it's written :...
2
by: John Kelsey | last post by:
I am an old, longtime C programmer surprised and confused by an error message I'm getting from my VS2005 compiler... "Cannot pass 'Item' as a ref or out argument because it is a 'foreach...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.