question realted to void *

J

junky_fellow

Guys,

Consider a function
func(void **var)
{

/* In function I need to typecast the variable var as (int **)
I mean to say, I need to access var as (int **)

}

My question is what is the better option, should I use
func(void **var) Or
func(void *var).

I think func(void *) should be fine, as we can store any type of
"pointer variable" in "void pointer variable".
void pointer variable should be big enough to hold any type of pointer
variable.

Is that correct? Or I am missing something?

And if that is correct, should we ever use void ** ?

thanks for any help/response.
 
A

aburry

Guys,

   Consider a function
func(void **var)
{

/* In function I need to typecast the variable var as (int **)
   I mean to say,  I need to access var as (int **)

}

My question is what is the better option, should I use
func(void **var)  Or
func(void *var).

I think func(void *) should be fine, as we can store any type of
"pointer variable" in "void pointer variable".
void pointer variable should be big enough to hold any type of pointer
variable.

Is that correct? Or I am missing something?

And if that is correct, should we ever use void ** ?

thanks for any help/response.

You can cast anything to anything you want, but the less confusing you
can make it, the better. Ideally, func() would take an "int** var" if
that is what it really is. However, sometimes, as appears to be true
in this case, it is necessary to use void. If you need to use void,
then I would still prefer "void**" if what you are passing really is a
pointer-to-pointer.

To me what matters more than how you cast "var" inside the function,
is what the function signature tells the client caller. If I'm going
to call a function with a signature "func(void*)" then I expect to
pass a pointer, not a pointer-to-pointer. For example:

void f1(void*);
void f2(void**);

int x = 0;
int* px = &x;

f1(px); /* pointer */
f2(&px); /* pointer to pointer */

Adam
 
K

Keith Thompson

And if that is correct, should we ever use void ** ?

void* can be used as a generic pointer type. What that means is that
a value of any pointer type (other than a pointer-to-function type)
can be converted to void* and back again without loss of information.

You might think that void** is therefore a generic pointer-to-pointer
type, but it isn't; in fact, there is no generic pointer-to-pointer
type.

You can convert an int*, or an int**, or an int***, or ... to void*
without loss of information -- except that you lose the type
information, which you have to carefully keep track of yourself.
 
C

CBFalconer

Malcolm said:
A void ** is for a list of pointers to arbitrary memory buffers.
A void * is for a pointer to an arbitary memory buffer.

No, a void** is for a pointer to a void*. When an array of void*
is passed anywhere, the reference is made with a void**. Just the
same as any other array reference.
 
P

Peter Nilsson

You can store any pointer to an object or incomplete type.

There is no requirement for void * to be big enough to
hold function pointers.
You can cast anything to anything you want,

You can try. But you can also fail in the attempt.
but the less confusing you can make it, the better.
Ideally, func() would take an "int** var" if that is
what it really is. However, sometimes, as appears to
be true in this case, it is necessary to use void. If
you need to use void, then I would still prefer
"void**" if what you are passing really is a
pointer-to-pointer.

Just realise that the guarantees that go with void * are
not necessarily available to void **.
To me what matters more than how you cast "var" inside
the function, is what the function signature tells the
client caller. If I'm going to call a function with a
signature "func(void*)" then I expect to pass a pointer,
not a pointer-to-pointer. For example:

    void f1(void*);
    void f2(void**);

    int x = 0;
    int* px = &x;

    f1(px);    /* pointer */
    f2(&px);   /* pointer to pointer */

This violates a constraint. There is no implicit
conversion to or from void ** as there is for void *.

But even if I cast &px in the call to f2, there is no
guarantee that the conversion of &px to void ** succeeds.

Whilst unlikely in practice, the standard allows void *
to have stricter alignment than int *. In that case, the
conversion of int ** to void ** can fail.
 
J

junky_fellow

With the possible exception of function pointers, yes (and broadly
speaking, this is why C doesn't guarantee that you can store function
pointers in a void *).


You're missing the obvious: void func(int **var)

Actually, I want to typecast "var" with some structure type. Just to
keep it simple I used "int".
However, the conclusion the I make is as follows. Please correct me if
I am wrong.

1) There is nothing wrong in using "void *" (in case var is not a
function pointer).
2) Using "void **" is a better option as it is more readable and we
don't lose the pointer-type information.

thanks a lot guys..
 
J

James Kuyper

Guys,

Consider a function
func(void **var)
{

/* In function I need to typecast the variable var as (int **)
I mean to say, I need to access var as (int **)

}

My question is what is the better option, should I use
func(void **var) Or
func(void *var).

I think func(void *) should be fine, as we can store any type of
"pointer variable" in "void pointer variable".
void pointer variable should be big enough to hold any type of pointer
variable.

Is that correct? Or I am missing something?

Any pointer to an object type can be converted to void* and back.
However, that does not mean that void* is compatible with all of those
other pointer type; it's only guaranteed to be compatible with pointers
to character types.

When you dereference a pointer, the pointed-at object has to have an
effective type that is compatible with the type pointed at by the
pointer, it can't have a type that is merely convertible to it. That's a
simplification of the real rules, but it's good enough for the purposes
of this explanation.

A void** is a pointer to a pointer to void. When you dereference it, it
has to be pointing at an actual pointer to void; it can't be pointing at
an pointer to int. int** is a pointer to a pointer to int. If you
convert an int** to a void**, dereferencing it might not work. You can't
convert it back to an int** and be sure that it compares equal to the
original pointer - that guarantee applies to void*, not void**. You
can't even guarantee that a void* has the same alignment requirements as
an int*; as a result, even the conversion of an int** to a void** could
have undefined behavior.

func(void*) is the right approach - just make sure you do it properly:

void func(void*p)
{
int **q = (int**)p;
// Use q for the real work.
}

I presume that there's some important reason why you can't simply
declare func(int **)? That would be the best approach, unless there's
something that prevents you from using it.

And if that is correct, should we ever use void ** ?

Yes, certainly:

int i;
void *p = &i;
void *arr[] = {&i, &p};

If you want to call func(&p) or func(arr), then you should declare it as
func(void**).
 
B

Ben Bacarisse

Actually, I want to typecast "var" with some structure type. Just to
keep it simple I used "int".
However, the conclusion the I make is as follows. Please correct me if
I am wrong.

1) There is nothing wrong in using "void *" (in case var is not a
function pointer).
2) Using "void **" is a better option as it is more readable and we
don't lose the pointer-type information.

Richard Heathfield has given you a detailed answer, but just in case
it helps clarify things, this question reads, to me, like this:

"I have object of type X. Is it better to use Y * or Y **?"
I.e. which of two wrong types is better? I think you are still not
asking the real question because you must be casting the pointer to
another type for some reason but we don't yet know why.
 
K

Keith Thompson

James Kuyper said:
Any pointer to an object type can be converted to void* and
back. However, that does not mean that void* is compatible with all of
those other pointer type; it's only guaranteed to be compatible with
pointers to character types.
[...]

I understand what you mean, but "compatible" isn't the word for it.
The standard has a very specific definition for "compatible types"; by
that definition, void* and char* are not compatible.

C99 6.7.5.1p2:

For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.

Since void and char are not compatible, void* and char* are not
compatible.
 
A

Andrey Tarasevich

Guys,

Consider a function
func(void **var)
{

/* In function I need to typecast the variable var as (int **)
I mean to say, I need to access var as (int **)

}

My question is what is the better option, should I use
func(void **var) Or
func(void *var).

func(void *var)
I think func(void *) should be fine, as we can store any type of
"pointer variable" in "void pointer variable".

Yes. Moreover, that's the only option that's really "fine", as opposed
to 'void**' one.
void pointer variable should be big enough to hold any type of pointer
variable.

Yes, as long as you are talking about pointer-to-data types.
And if that is correct, should we ever use void ** ?

Hm... Yes. As well as 'void***', 'void****' and so on. Why not? The
general concept of "rising the level of indirection" is not really
related to the concept of "generic pointer type".
 
J

James Kuyper

Keith said:
James Kuyper said:
Any pointer to an object type can be converted to void* and
back. However, that does not mean that void* is compatible with all of
those other pointer type; it's only guaranteed to be compatible with
pointers to character types.
[...]

I understand what you mean, but "compatible" isn't the word for it.
The standard has a very specific definition for "compatible types"; by
that definition, void* and char* are not compatible.

C99 6.7.5.1p2:

For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.

Since void and char are not compatible, void* and char* are not
compatible.

You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those cases
where the standard falls short of actually saying something that I think
it was actually intended to say. As a practical matter, they work just
as if they were compatible, on most implementations.

When I wrote: "That's a simplification of the real rules, but it's good
enough for the purposes of this explanation.", I should have made it
clear that this statement applied to both of the preceeding paragraphs,
not just the immediately preceding one.
 
H

Harald van Dijk

Keith said:
James Kuyper said:
Any pointer to an object type can be converted to void* and back.
However, that does not mean that void* is compatible with all of those
other pointer type; it's only guaranteed to be compatible with
pointers to character types.
[...]

I understand what you mean, but "compatible" isn't the word for it. The
standard has a very specific definition for "compatible types"; by that
definition, void* and char* are not compatible.

C99 6.7.5.1p2:

For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.

Since void and char are not compatible, void* and char* are not
compatible.

You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those cases
where the standard falls short of actually saying something that I think
it was actually intended to say. As a practical matter, they work just
as if they were compatible, on most implementations.

My compiler reports an error when I try

void f(char *p);
void f(void *p) {}

My compiler doesn't report an error when I try

void f(void *p);
void f(void *p) {}

or when I try

void f(int (*p)[]);
void f(int (*p)[30]) {}

I have trouble believing the intent was to allow the first, or that you
believe that was intended. If char * and void * were compatible, it would
be allowed, because compatible means something different from how you are
using it.
 
K

Keith Thompson

James Kuyper said:
Keith said:
James Kuyper said:
Any pointer to an object type can be converted to void* and
back. However, that does not mean that void* is compatible with all of
those other pointer type; it's only guaranteed to be compatible with
pointers to character types.
[...]
I understand what you mean, but "compatible" isn't the word for it.
The standard has a very specific definition for "compatible types"; by
that definition, void* and char* are not compatible.
C99 6.7.5.1p2:
For two pointer types to be compatible, both shall be identically
qualified and both shall be pointers to compatible types.
Since void and char are not compatible, void* and char* are not
compatible.

You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those
cases where the standard falls short of actually saying something that
I think it was actually intended to say. As a practical matter, they
work just as if they were compatible, on most implementations.

When I wrote: "That's a simplification of the real rules, but it's
good enough for the purposes of this explanation.", I should have made
it clear that this statement applied to both of the preceeding
paragraphs, not just the immediately preceding one.

Another way in which they aren't compatible is this:

int main(void)
{
char *pc;
void *pv;

char **ppc = &pc;
void **ppv = &pv;

ppc = ppv; /* constraint violation */
ppv = ppc; /* constraint violation */

return 0;
}

char* and void* can be assigned to each other, but only because
there's an implicit conversion (which, given the requirement for them
to have the same representation, will merely reinterpret the bits).

Since char* and void* are incompatible, pointers to those types are
incompatible, and cannot be assigned to each other because there is no
implicit conversion.

The standard implies that various types of type-punning between char*
and void* (and unsigned char*, and signed char*) are safe, but that
doesn't affect the many contexts that require compatible types.
 
J

jameskuyper

Harald said:
You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those cases
where the standard falls short of actually saying something that I think
it was actually intended to say. As a practical matter, they work just
as if they were compatible, on most implementations.

My compiler reports an error when I try

void f(char *p);
void f(void *p) {}

My compiler doesn't report an error when I try

void f(void *p);
void f(void *p) {}

or when I try

void f(int (*p)[]);
void f(int (*p)[30]) {}

I have trouble believing the intent was to allow the first, or that you
believe that was intended. If char * and void * were compatible, it would
be allowed, because compatible means something different from how you are
using it.

What I meant is a little more complicated than what I said. You can
work around the fact that those functions are incompatible by using
some type punning. The behavior of code that performs such type
punning is undefined, but I believe that it was the intent of the
committee that such type punning would work.
 
H

Harald van Dijk

Harald said:
You're right: the standard requires them to have the same alignment
requirements and same representation, but they are not compatible
according to C's definition of the term. This is another of those
cases where the standard falls short of actually saying something
that I think it was actually intended to say. As a practical matter,
they work just as if they were compatible, on most implementations.

My compiler reports an error when I try

void f(char *p);
void f(void *p) {}
[snip]

What I meant is a little more complicated than what I said. You can work
around the fact that those functions are incompatible by using some type
punning. The behavior of code that performs such type punning is
undefined, but I believe that it was the intent of the committee that
such type punning would work.

The standard says "The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions, return values
from functions, and members of unions." in two footnotes.

This suggests, for example, that this is valid code (and that g may be
called):

void f(void *p) {}
void g(void) {
((void(*)(char *)) f) ("Hello");
}

It doesn't actually work though, in at least gcc. But if that is really
meant to be valid, then I can agree that it is probably the intent to also
allow

void *p = 0;
char *q = *(char **) &p;
 
J

jameskuyper

Harald van D©¦k wrote:
....
The standard says "The same representation and alignment requirements are
meant to imply interchangeability as arguments to functions, return values
from functions, and members of unions." in two footnotes.

Yes, that's precisely what I was thinking of. The problem is that it's
non-normative text. The normative text only requires same
representation and same alignment requirements. It's possible to
define function interface conventions that meet those two requirement,
while not allowing void* and char* to be interchangeable. For
instance, passing void* return values using a different register than
char*. Therefore, the standard falls short of actually guaranteeing
interchangeability.
This suggests, for example, that this is valid code (and that g may be
called):

void f(void *p) {}
void g(void) {
((void(*)(char *)) f) ("Hello");
}

It doesn't actually work though, in at least gcc.

I'm curious - do you know the details of why it fails? I've known for
a long time that a lack of interchangeabiltiy is permitted, but it
would help to be able to cite the details of a real example of it,
particularly if its a compiler as widely available as gcc.
 
K

Keith Thompson

pete said:
The standard would still fall short
of actually guaranteeing interchangeability,
even if it had been in a normative part of the text
instead of in a footnote.

If it had been in the normative part of the standard,
instead of in a footnote,
the question would then be:
why does it say
"are meant to imply"
instead of
"imply"?

Obviously the wording would have to be changed in addition to just
moving it from the footnote. And dropping "are meant to" wouldn't
really help; the fact is that the representation and alignment
requirements *don't* imply interchangeability. There would have to
be an explicit requirements that the types *are* interchangeable.
 
C

Chad

[...]
And if that is correct, should we ever use void ** ?

void* can be used as a generic pointer type. What that means is that
a value of any pointer type (other than a pointer-to-function type)
can be converted to void* and back again without loss of information.

You might think that void** is therefore a generic pointer-to-pointer
type, but it isn't; in fact, there is no generic pointer-to-pointer
type.

You can convert an int*, or an int**, or an int***, or ... to void*
without loss of information -- except that you lose the type
information, which you have to carefully keep track of yourself.

--

How would you track the type information in this case?
 
P

Peter Nilsson

Keith Thompson said:
... the fact is that the representation and alignment
requirements *don't* imply interchangeability.  There
would have to be an explicit requirements that the
types *are* interchangeable.

I'd prefer to see unprototyped functions finally removed
from C. Then I'd be happy with a statement that functions
in the standard library that are variadic, or use va_list,
use va_arg.

Although, I'd also prefer if va_arg could accept struct
pointers that are convertable to a common initial sequence,
but obviously that would imply a greater restriction to
the language (though I've never seen an implementation
where it might be an imposition.)
 
H

Harald van Dijk

Harald van Dijk wrote:
...

I'm curious - do you know the details of why it fails?

test.c: In function ‘g’:
test.c:3: warning: function called through a non-compatible type
test.c:3: note: if this code is reached, the program will abort

When gcc detects that a function is called through an incompatible
function pointer, and the function definition is available, it rejects the
call to prevent internal compiler errors when trying if inlining and such
makes sense. At least, that's how I remember it, but my memory may be off.
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top