Casting void * to void ** ?

T

Twister

Hi All,

I have a question which might sound very basic.

I have a simple structure:

struct simple{
void *buffer;
};
typedef struct simple Simple;

In my function I do this:

void do_Something(){

Simple *simp_struct;
simp_struct->buffer = malloc(10 * sizeof(int *));

call_func((void **)((int **)(simp_struct->buffer)));
....
}

The function call_func has this prototype:
call_func(void **buf);

I am confused with this piece of code:
call_func((void **)((int **)(simp_struct->buffer)));

What does this construct mean? How is that simp_struct->buffer
(which is a void *) is being cast to a int** followed by a
cast to void ** and passed to call_func ?

Rgds.
Mirage
 
T

Twister

Twister said:
Hi All,

I have a question which might sound very basic.

I have a simple structure:

struct simple{
void *buffer;
};
typedef struct simple Simple;

In my function I do this:

void do_Something(){

Simple *simp_struct;
simp_struct->buffer = malloc(10 * sizeof(int *));

call_func((void **)((int **)(simp_struct->buffer)));
....
}

The function call_func has this prototype:
call_func(void **buf);

I am confused with this piece of code:
call_func((void **)((int **)(simp_struct->buffer)));

What does this construct mean? How is that simp_struct->buffer
(which is a void *) is being cast to a int** followed by a
cast to void ** and passed to call_func ?

Rgds.
Mirage

I mistyped part of my previous mail:

This piece of code:
> I am confused with this piece of code:
> call_func((void **)((int **)(simp_struct->buffer)));

should be this:

for(i=0; i<10 ;i++)
call_func((void **)((int **)simp_struct->buffer + i));

My question remains the same. What does the above
construct mean?

Rgds.
Mirage
 
W

Walter Roberson

Twister said:
struct simple{
void *buffer;
};
typedef struct simple Simple;
void do_Something(){

Simple *simp_struct;

simp_struct is an uninitialized pointer after that statement.
simp_struct->buffer = malloc(10 * sizeof(int *));

But there you are using it as if it was initialized.
simp_struct->buffer involves dereferencing simp_struct first and
then accessing the structure component named buffer there, so
simp_struct needs to be given a value first.
 
R

Richard Heathfield

Twister said:

simp_struct->buffer = malloc(10 * sizeof(int *));

call_func((void **)((int **)(simp_struct->buffer)));

Why not just do this:

call_func(&simp_struct->buffer);

Casts are almost always wrong.

The function call_func has this prototype:
call_func(void **buf);

I am confused with this piece of code:
call_func((void **)((int **)(simp_struct->buffer)));

What does this construct mean?

It means you don't (or whoever wrote it doesn't) understand what casting is
for.
 
R

Richard Heathfield

Walter Roberson said:
simp_struct is an uninitialized pointer after that statement.

Good spot. I didn't see that. Silly me.

Everything I said still applies, but that applies too!
 
R

Richard Heathfield

Twister said:
for(i=0; i<10 ;i++)
call_func((void **)((int **)simp_struct->buffer + i));

My question remains the same. What does the above
construct mean?

That's a major difference.

What you have now is a bug.

simp_struct->buffer has type void *, so you can't do pointer arithmetic on
it. So the cast to int ** gives you a value (of type int **) with which you
/can/ do pointer arithmetic. That is, (int **)simp_struct->buffer + i gives
you the address of the i'th int **, starting at simp_struct->buffer. The
expression has type int **. The cast to void ** is an error because there
is no guarantee that an int ** can be copied to a void ** without loss of
information.
 
T

Twister

Richard said:
Twister said:




That's a major difference.

What you have now is a bug.

simp_struct->buffer has type void *, so you can't do pointer arithmetic on
it. So the cast to int ** gives you a value (of type int **) with which you
/can/ do pointer arithmetic. That is, (int **)simp_struct->buffer + i gives
you the address of the i'th int **, starting at simp_struct->buffer. The
expression has type int **. The cast to void ** is an error because there
is no guarantee that an int ** can be copied to a void ** without loss of
information.

simp_struct->buffer was earlier initialized to point to memory
of 10 (int *)'s. So isn't just saying, (int *)simp_struct->buffer + i
correct? Why cast it to an (int **), unless i'm not passing it
to a function which expects a int ** or a void ** ? Please correct
me if i'm wrong here.

Rgds.
Mirage
 
R

Richard Heathfield

Twister said:
simp_struct->buffer was earlier initialized to point to memory
of 10 (int *)'s. So isn't just saying, (int *)simp_struct->buffer + i
correct?

No, that would point to the i'th int, not the i'th int *.
Why cast it to an (int **),

To get a pointer to the i'th int *.
Please correct me if i'm wrong here.

The cast to int ** is correct, but doesn't help you solve your void **
problem.
 
T

Twister

Richard said:
Twister said:




No, that would point to the i'th int, not the i'th int *.




To get a pointer to the i'th int *.




The cast to int ** is correct, but doesn't help you solve your void **
problem.

Thanks. That clarified part of my question.
>The cast to void ** is an error because there is no guarantee that an
>int ** can be copied to a void ** without loss of information.

The malloc just allocated enough space for 10 (int *) pointers.
The pointers themselves are not pointing to valid memory. So If I cast
simp_struct->buffer finally to a void **(after the cast to an int **)
and pass it to a function which allocates some momory and points these
int *'s to valid memory, am I not doing the right thing ? Where is the
loss of information happening ?

Rgds.
Mirage
 
R

Richard Heathfield

Twister said:
The malloc just allocated enough space for 10 (int *) pointers.
Yes.

The pointers themselves are not pointing to valid memory.
Right.

So If I cast
simp_struct->buffer finally to a void **(after the cast to an int **)
and pass it to a function which allocates some momory and points these
int *'s to valid memory, am I not doing the right thing ?

No, I'm afraid not.
Where is the loss of information happening ?

There's no guarantee that information is lost. There's just no guarantee
that it's not lost! Either could happen. In other words, it might "work"
just fine on your development machine - and then break on some other box.

The problem is that, whilst the Standard guarantees that you can use void *
to store any object pointer (without loss of information), it doesn't offer
the same guarantee for void **.
 
J

Joe Smith

Richard Heathfield said:
Walter Roberson said:


Good spot. I didn't see that. Silly me.

Everything I said still applies, but that applies too!

I've been looking for some common notions that I thought I had read in your
book. I was hoping you might help me find them. Joe
----------
C drifts
and seems

But now,
I'm piffed
and meeved

and in a bad mood
 
R

Richard Heathfield

Joe Smith said:
I've been looking for some common notions that I thought I had read in
your
book. I was hoping you might help me find them. Joe

I've been in RL for a few days, and I seem to have lost the plot here. If
you could make it clearer what you're after, I'll be happy to do what I can
to help you in your search.
 
C

CBFalconer

Richard said:
Joe Smith said:


I've been in RL for a few days, and I seem to have lost the plot
here. If you could make it clearer what you're after, I'll be
happy to do what I can to help you in your search.

OT - what is an RL?
 
R

Richard Heathfield

CBFalconer said:
OT - what is an RL?

It's what happens to you when you pop into the Big Room for a while (the one
with the really high grey-blue ceiling and imitation artificial light).
 
M

Michael Mair

Richard said:
CBFalconer said:

It's what happens to you when you pop into the Big Room for a while (the one
with the really high grey-blue ceiling and imitation artificial light).

Oh, the one with the incredibly high resolution and artifact-free
animation? I don't know, about half the time the sprinkler system or
the air conditioning is defect. The worst thing, though, is that you
cannot change the options.

-Michael
 
R

Richard Heathfield

Michael Mair said:
Oh, the one with the incredibly high resolution and artifact-free
animation? I don't know, about half the time the sprinkler system or
the air conditioning is defect. The worst thing, though, is that you
cannot change the options.

A source (who wishes to remain anonymous!) has asked me, on the off-chance
that the maintenance team read clc, to add that the thermostat is broken.
 
J

Joe Smith

[funny stuff snipped]

I've been writing elementary programs to knock some of the rust off my game
here. Both Professors Knuth and Gallian start with Euclid's algortihm. I
would like to implement it with the memory techniques at the beginning of
_Unleashed_ Should I start clean with a new thread? I must say, while I
didn't catch why a person would want cast a void * to void**, it doesn't
sound like a very good idea. Joe
 
R

Richard Heathfield

Joe Smith said:
[funny stuff snipped]

I've been writing elementary programs to knock some of the rust off my
game
here. Both Professors Knuth and Gallian start with Euclid's algortihm. I
would like to implement it with the memory techniques at the beginning of
_Unleashed_

I'm not sure why you'd need memory techniques for Euclid's Algorithm.

You can find an implementation on p326 of CU. Alternatively, here's my own,
relatively straightforward, implementation of Knuth's description of
Euclid's Algorithm in TAOCP:

unsigned long gcd(unsigned long m, unsigned long n)
{
if(n == 0)
{
/* Caller doesn't know what he's doing. It's not
* our job to bomb out, so we'll simply return an
* impossible result - 0 - to match our impossible
* input.
*/
}
else if(m < n)
{
n = gcd(n, m);
}
else
{
unsigned long r = m % n;
if(r > 0)
{
n = gcd(n, r);
}
}
return n;
}

Should I start clean with a new thread? I must say, while I
didn't catch why a person would want cast a void * to void**, it doesn't
sound like a very good idea.

I see no need for it, and you're right - it sounds like a bad idea. Not bad
in itself, exactly, but it's a hint that someone, somewhere, is either
assuming or just hoping(!) that void ** carries with it the same guarantees
that void * does - but, alas, this is not the case.
 
J

Joe Smith

"Richard Heathfield" opined:
Joe Smith said:

I'm not sure why you'd need memory techniques for Euclid's Algorithm.

You can find an implementation on p326 of CU. Alternatively, here's my
own,
relatively straightforward, implementation of Knuth's description of
Euclid's Algorithm in TAOCP:

unsigned long gcd(unsigned long m, unsigned long n)
{
if(n == 0)
{
/* Caller doesn't know what he's doing. It's not
* our job to bomb out, so we'll simply return an
* impossible result - 0 - to match our impossible
* input.
*/
}
else if(m < n)
{
n = gcd(n, m);
}
else
{
unsigned long r = m % n;
if(r > 0)
{
n = gcd(n, r);
}
}
return n;
}



I see no need for it, and you're right - it sounds like a bad idea. Not
bad
in itself, exactly, but it's a hint that someone, somewhere, is either
assuming or just hoping(!) that void ** carries with it the same
guarantees
that void * does - but, alas, this is not the case.

'void**' reminds me of the Escher drawing of the hand drawing the hand and
the peculiar way Goedel regarded his. I'll fire up that source you posted
when I begin my campaign tomorrow to Take Over the Week. My methods for
handling memory are childish. I think what I'll try to do is take the
eratosthenos algorithm down yonder and have the user tell the prog how large
an N we have. Joe
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top