471,593 Members | 1,798 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

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

Generalized function for deallocating and setting pointer to NULL

I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting
it's value to NULL regardless of the pointer's type. I thought "void
** " should do the trick, but I kept getting the following warning
message from gcc:

warning: passing argument 1 of 'free_var' from incompatible pointer
type

which obviously could be solved by doing an explicit cast to (void **)
in the argument list when calling the fuction. That however would put
an extra burden on the programmer, so I invented the following
solution which works quite well apparently. Please give me your
opinions on this issue.

void free_var(void *vptr)
{
void **ptr = (void **) vptr;

if (ptr != NULL) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
}
}

Thank you.
Nov 29 '07 #1
27 2017
ro*********@gmail.com wrote:
I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting
it's value to NULL regardless of the pointer's type. I thought "void
** " should do the trick, but I kept getting the following warning
message from gcc:

warning: passing argument 1 of 'free_var' from incompatible pointer
type
That's because in C the only pointer type capable of pointing to any
type of data is the void *, not a void **. void ** can only point to a
void * data type.
which obviously could be solved by doing an explicit cast to (void **)
Not solved, merely suppressed.
in the argument list when calling the fuction. That however would put
an extra burden on the programmer, so I invented the following
solution which works quite well apparently. Please give me your
opinions on this issue.

void free_var(void *vptr)
{
void **ptr = (void **) vptr;

if (ptr != NULL) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
}
}
C's pass by value convention means that this function does not actually
operate on the caller's 'vptr', merely this function's localised copy.
So the caller's 'vptr' is left indeterminate after a call to this
function.

Nov 29 '07 #2
rocco.rossi:
I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting it's
value to NULL regardless of the pointer's type. I thought "void ** "
should do the trick, but I kept getting the following warning message
from gcc:

void DeallocateAndNullify(void **const pp)
{
free (*pp);

*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need to check
it for null.

You could use macros to pretend that C has "pass by reference", but I
wouldn't suggest it -- because a C programmer assumes their object won't
get altered unless they pass its address.

--
Tomás Ó hÉilidhe
Nov 29 '07 #3
ro*********@gmail.com wrote:
I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting
it's value to NULL regardless of the pointer's type. I thought "void
** " should do the trick, but I kept getting the following warning
message from gcc:

warning: passing argument 1 of 'free_var' from incompatible pointer
type

which obviously could be solved by doing an explicit cast to (void **)
in the argument list when calling the fuction. That however would put
an extra burden on the programmer, so I invented the following
solution which works quite well apparently. Please give me your
opinions on this issue.

void free_var(void *vptr)
{
void **ptr = (void **) vptr;

if (ptr != NULL) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
}
}
That method will work if you use it as follows:

void *vp = malloc(42);
free_var(&vp);

However, the more typical use of malloc is not guaranteed to work:

int *ip = malloc(42*sizeof(int));
free(&ip); // WRONG

This is because the *ptr expression in free_var has defined behavior
only if the pointed-at pointer actually has the type void*. On many
implementations, all pointers have the same representation, so this cast
happens to work. However, the standard allows each pointer type to have
it's own representation (with certain exceptions that aren't relevant here).

The void* type allows a certain amount of genericity in C, but not
enough to implement this idea as a C function. For this kind of
genericity, you need a macro:

#define FREE_VAR(p) (free(p), (p)=NULL)
Nov 29 '07 #4
Charlie Gordon wrote:
"Toms hilidhe" <to*@lavabit.coma crit:
>rocco.rossi:
>>I've been trying to write a function capable of checking if a
pointer value is set to NULL, and if it isn't, of deallocating
and setting it's value to NULL regardless of the pointer's type.
I thought "void ** " should do the trick, but I kept getting the
following warning message from gcc:

void DeallocateAndNullify(void **const pp)
{
free (*pp);
*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need
to check it for null.

You are right about free(NULL). But your solution is what the OP
tried first and it is not portable because pointer to different
types don't all have the same representation. It means that
void** may not be inappropriate to store the address of an int*.
gcc will give you a warning if you invoke
DeallocateAndNullify(&intp) with int *intp;
No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 29 '07 #5
CBFalconer wrote:
Charlie Gordon wrote:
"Tom�s � h�ilidhe" <to*@lavabit.coma �crit:
...
void DeallocateAndNullify(void **const pp)
{
free (*pp);
*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need
to check it for null.
You are right about free(NULL). But your solution is what the OP
tried first and it is not portable because pointer to different
types don't all have the same representation. It means that
void** may not be inappropriate to store the address of an int*.
gcc will give you a warning if you invoke
DeallocateAndNullify(&intp) with int *intp;

No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.
I'm curious - if sizeof(void*) == 6 and sizeof(int*) == 4, how does
that work? Naively, I'd have expected *pp=0 to attempt to set two
extra bytes that aren't actually part of intp.

Nov 29 '07 #6
CBFalconer <cb********@yahoo.comwrites:
Charlie Gordon wrote:
>"Tomás Ó hÉilidhe" <to*@lavabit.coma écrit:
>>rocco.rossi:
I've been trying to write a function capable of checking if a
pointer value is set to NULL, and if it isn't, of deallocating
and setting it's value to NULL regardless of the pointer's type.
I thought "void ** " should do the trick, but I kept getting the
following warning message from gcc:

void DeallocateAndNullify(void **const pp)
{
free (*pp);
*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need
to check it for null.

You are right about free(NULL). But your solution is what the OP
tried first and it is not portable because pointer to different
types don't all have the same representation. It means that
void** may not be inappropriate to store the address of an int*.
gcc will give you a warning if you invoke
DeallocateAndNullify(&intp) with int *intp;

No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.
No, you can't. There is no implicit conversion to or from type
void**; there are only implicit conversions to and from type void*,
which is a distinct type.

void* is a generic pointer type. C has *no* generic
pointer-to-pointer type. Something of type void** points to an object
of type void*, and to nothing else.

One way to do what the OP wants is to use a macro, such as;

#define DEALLOCATE(p) (free(p), (p) = NULL)

This fails if the argument is an expression with side effects; the
uppercase name is a hint to avoid calling it with such an argument.

Another way is simply to set the pointer to NULL after freeing it:

free(p);
p = NULL;

or even:

free(p); p = NULL;

(The latter makes it clearer that the two statements are associated,
if you don't mind occasionally putting two statements on one line.
Possibly this could cause problems for debuggers.)

It's easy to forget to set the pointer to NULL after freeing it, but
it's also easy to forget to use DEALLOCATE() rather than free(). But
if you always want to use DEALLOCATE() rather than free(), you can
search your source code for calls to free().

Note that this will prevent some errors, but by no means all of them.
(Actually it doesn't so much prevent errors as make them easier to
detect.) But if a copy of the pointer value has been stored in another
variable, then that copy will not be set to NULL:

p = malloc(...);
p2 = p;
...
DEALLOCATE(p);
/* p == NULL */
/* p2 is indeterminate, and probably still points to the
deallocated memory */

Apart from setting its argument to NULL and evaluating its argument
twice, there is one more difference between free() and DEALLOCATE().
The argument to free() needn't be an lvalue. For example, this is
perfectly legal:

int *p = malloc(10 * sizeof *p);
/* ... */
if (p != NULL) {
p ++;
/* ... */
free(p-1);
}

This call to free() cannot legally be replaced with a call to
DEALLOCATE. Then again, I'd probably consider it poor style anyway.
I suspect that 99+% of calls to free() pass an lvalue expression that
refers to a pointer object (or whose value is NULL).

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Looking for software development work in the San Diego area.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Nov 29 '07 #7
Keith Thompson wrote:
CBFalconer <cb********@yahoo.comwrites:
>Charlie Gordon wrote:
>>"Tomás Ó hÉilidhe" <to*@lavabit.coma écrit:
.... snip ...
>>>
void DeallocateAndNullify(void **const pp)
{
free (*pp);
*pp = 0;
}

Passing a null pointer to free has no effect, so there's no need
to check it for null.
.... snip ...
>>
No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.

No, you can't. There is no implicit conversion to or from type
void**; there are only implicit conversions to and from type void*,
which is a distinct type.
You're right, and I was sloppy.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Nov 29 '07 #8
"CBFalconer" <cb********@yahoo.coma crit dans le message de news:
47**************@yahoo.com...
Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
>>Charlie Gordon wrote:
"Tomás " h?ilidhe" <to*@lavabit.coma écrit:
... snip ...
>>>>
void DeallocateAndNullify(void **const pp)
{
free (*pp);
*pp = 0;
}
>
Passing a null pointer to free has no effect, so there's no need
to check it for null.
... snip ...
>>>
No, you can pass that routine any pointer address, and it will be
auto-converted to void**. After that the free will work
correctly. Also, since void** is a pointer to void*, the NULL
assignment works. But it is more clearly written using NULL rather
than 0.

No, you can't. There is no implicit conversion to or from type
void**; there are only implicit conversions to and from type void*,
which is a distinct type.

You're right, and I was sloppy.
Apology accepted.

--
Chqrlie.
Nov 29 '07 #9
On Thu, 29 Nov 2007 00:37:48 -0800 (PST), ro*********@gmail.com wrote:
>I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting
it's value to NULL regardless of the pointer's type. I thought "void
** " should do the trick, but I kept getting the following warning
message from gcc:

warning: passing argument 1 of 'free_var' from incompatible pointer
type

which obviously could be solved by doing an explicit cast to (void **)
in the argument list when calling the fuction. That however would put
an extra burden on the programmer, so I invented the following
solution which works quite well apparently. Please give me your
opinions on this issue.

void free_var(void *vptr)
{
void **ptr = (void **) vptr;
The cast here serves no purpose. There is an implicit conversion from
vptr to any other type of object pointer.
>
if (ptr != NULL) {
if (*ptr != NULL) {
Here is where you can run into trouble. *ptr is by definition of type
void*. Let's assume sizeof(void*) is 8. Furthermore, assume you
actually call the function with something like
int *x = &some_int;
free_var(&x)
If sizeof(int*) is only 4, the code generated will try to evaluate an
8-byte object when the object only has four bytes. This is known as
undefined behavior.
> free(*ptr);
*ptr = NULL;
These two statements don't fare any better.
> }
}
}
You can achieve the desired result with
int *x = &some_int; /* or NULL */
x = free_var(x);

void* free_var(void *ptr){
free(ptr); /* if ptr == NULL, this is still defined */
return NULL;}

Some have suggested using a macro
#define FREE_VAR(x) (free(x), x = NULL)
which will work as long as the expression x does not have side
effects.
Remove del for email
Dec 1 '07 #10
On Thu, 29 Nov 2007 09:27:09 GMT, Toms hilidhe <to*@lavabit.com>
wrote:
>rocco.rossi:
>I've been trying to write a function capable of checking if a pointer
value is set to NULL, and if it isn't, of deallocating and setting it's
value to NULL regardless of the pointer's type. I thought "void ** "
should do the trick, but I kept getting the following warning message
from gcc:


void DeallocateAndNullify(void **const pp)
{
free (*pp);

*pp = 0;
}
How would I pass an int* (or its address) to this function and avoid
the undefined behavior when sizeof(void*) != sizeof(int*)?
Remove del for email
Dec 1 '07 #11
Barry Schwarz wrote:
Toms hilidhe <to*@lavabit.comwrote:
>rocco.rossi:
>>I've been trying to write a function capable of checking if a
pointer value is set to NULL, and if it isn't, of deallocating
and setting it's value to NULL regardless of the pointer's type.
I thought "void ** " should do the trick, but I kept getting the
following warning message from gcc:

void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}

How would I pass an int* (or its address) to this function and
avoid the undefined behavior when sizeof(void*) != sizeof(int*)?
....
int *p;
....
DeallocAndNullify(&p);

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Dec 1 '07 #12
On Sat, 01 Dec 2007 02:41:31 -0500, CBFalconer wrote:
Barry Schwarz wrote:
>Tomás Ó hÉilidhe <to*@lavabit.comwrote:
>>void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}

How would I pass an int* (or its address) to this function and avoid
the undefined behavior when sizeof(void*) != sizeof(int*)?

....
int *p;
....
DeallocAndNullify(&p);
Well yes, if your code won't compile, you won't have undefined behaviour,
but I doubt that's what Barry Schwarz meant.

There is no implicit conversion from int ** to void **. There is no point
in an implicit conversion from int ** to void ** either, since the
representations of int * and void * can be completely different.
Dec 1 '07 #13
CBFalconer <cb********@yahoo.comwrites:
Barry Schwarz wrote:
>Tomás Ó hÉilidhe <to*@lavabit.comwrote:
>>rocco.rossi:
I've been trying to write a function capable of checking if a
pointer value is set to NULL, and if it isn't, of deallocating
and setting it's value to NULL regardless of the pointer's type.
I thought "void ** " should do the trick, but I kept getting the
following warning message from gcc:

void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}

How would I pass an int* (or its address) to this function and
avoid the undefined behavior when sizeof(void*) != sizeof(int*)?

....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**. There is
no implicit conversion from int** to void**.

Also, your call is to DeallocAndNullify rather than
DeallocateAndNullify. (Perhaps you tried compiling your code, and the
misspelling caused the compiler not to know what the function
expects.)

[Chuck: aioe.org is free, doesn't add its own signature, and doesn't
even require signing up; you just have to set $NNTPSERVER. See their
web page for details. I've been using it myself while rr.com is under
a UDP. Please consider it.]

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Looking for software development work in the San Diego area.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Dec 1 '07 #14
Keith Thompson wrote:
CBFalconer <cb********@yahoo.comwrites:
>Barry Schwarz wrote:
>>Tomás Ó hÉilidhe <to*@lavabit.comwrote:
rocco.rossi:
I've been trying to write a function capable of checking if a
pointer value is set to NULL, and if it isn't, of deallocating
and setting it's value to NULL regardless of the pointer's type.
I thought "void ** " should do the trick, but I kept getting the
following warning message from gcc:
void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}
How would I pass an int* (or its address) to this function and
avoid the undefined behavior when sizeof(void*) != sizeof(int*)?
....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**. There is
no implicit conversion from int** to void**.
But int* and void* are compatible.(?) Therefore..
DeallocAndNullify((void*)&p);
...should work.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Dec 1 '07 #15
Joe Wright wrote:
Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
>>Barry Schwarz wrote:
Tomás ? h?ilidhe <to*@lavabit.comwrote:
rocco.rossi:
>I've been trying to write a function capable of checking if a
>pointer value is set to NULL, and if it isn't, of deallocating
>and setting it's value to NULL regardless of the pointer's type.
>I thought "void ** " should do the trick, but I kept getting the
>following warning message from gcc:
void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}
How would I pass an int* (or its address) to this function and
avoid the undefined behavior when sizeof(void*) != sizeof(int*)?
....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**. There
is no implicit conversion from int** to void**.

But int* and void* are compatible.(?) Therefore..
DeallocAndNullify((void*)&p);
..should work.
Pass by value semantics mean that the functions becomes useless.

Dec 1 '07 #16
On Sat, 01 Dec 2007 10:42:02 -0500, Joe Wright wrote:
But int* and void* are compatible.(?) Therefore..
DeallocAndNullify((void*)&p);
..should work.
int* and void* are not compatible any more than int and double are. There
are implicit conversions between the two, but portable code can't
reinterpret the bit pattern of one as the other.
Dec 1 '07 #17
Joe Wright wrote, On 01/12/07 15:42:
Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
>>Barry Schwarz wrote:
Tomás Ó hÉilidhe <to*@lavabit.comwrote:
rocco.rossi:
>I've been trying to write a function capable of checking if a
>pointer value is set to NULL, and if it isn't, of deallocating
>and setting it's value to NULL regardless of the pointer's type.
>I thought "void ** " should do the trick, but I kept getting the
>following warning message from gcc:
void DeallocateAndNullify(void **const pp) {
free (*pp);
*pp = 0;
}
How would I pass an int* (or its address) to this function and
avoid the undefined behavior when sizeof(void*) != sizeof(int*)?
....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**. There is
no implicit conversion from int** to void**.

But int* and void* are compatible.(?)
There is an implicit conversion between them which is not quite the same
thing.
Therefore..
DeallocAndNullify((void*)&p);
..should work.
No, see the comp.lang.c FAQ question 4.9 and http://c-faq.com/
I'm surprised not of the regulars have posted this reference yet.
--
Flash Gordon
Dec 1 '07 #18
Joe Wright wrote:
....
But int* and void* are compatible.(?)
What made you think that?
Dec 1 '07 #19
Keith Thompson wrote:
CBFalconer <cb********@yahoo.comwrites:
.... snip ...
>>
....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**.
There is no implicit conversion from int** to void**.

Also, your call is to DeallocAndNullify rather than
DeallocateAndNullify. (Perhaps you tried compiling your code, and
the misspelling caused the compiler not to know what the function
expects.)
Consider the following test (marked as quotation for linewrap):
[1] c:\c\junk>cat junk.c
#include <stdio.h>
#include <stdlib.h>

void release(void* *p) {
puts("Was Alive");
free(*p);
*p = NULL;
} /* release */

/* ------------------- */

int main(void) {
int *ptr;

if (ptr = malloc(sizeof *ptr)) release(&ptr);
if (ptr) puts("Alive");
else puts("Dead");

return 0;
} /* main, fcopylns */

[1] c:\c\junk>cc junk.c
junk.c: In function `main':
junk.c:15: warning: suggest parentheses around assignment used as truth value
junk.c:15: warning: passing arg 1 of `release' from incompatible pointer type

[1] c:\c\junk>a
Was Alive
Dead
Now I maintain the error is really a chimera. In release the void*
is never dereferenced, but is simply passed to free (which knows
what to do with it) and is set to NULL before exiting. The
parameter is simply a pointer to a void*.

Of course it would not do to ignore the error in passing the
parameter without analyzing the use in release, and that is
probably excessive detail.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.
--
Posted via a free Usenet account from http://www.teranews.com

Dec 1 '07 #20
Keith Thompson wrote:
>
.... snip ...
>
[Chuck: aioe.org is free, doesn't add its own signature, and
doesn't even require signing up; you just have to set $NNTPSERVER.
See their web page for details. I've been using it myself while
rr.com is under a UDP. Please consider it.]
The problem is the associated nonsense. I plan to eventually
upgrade the newsreader. When I do I will be faced with that
nonsense, and one more piece won't cause much fuss. Who know,
maybe my ISP will start to function again! Meanwhile, I am VERY
lazy.

--
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Try the download section.

--
Posted via a free Usenet account from http://www.teranews.com

Dec 1 '07 #21
CBFalconer wrote:
Keith Thompson wrote:
>CBFalconer <cb********@yahoo.comwrites:
... snip ...
>>>
....
int *p;
....
DeallocAndNullify(&p);
[...]

Nope. &p is of type int**; the parameter is of type void**.
There is no implicit conversion from int** to void**.

Also, your call is to DeallocAndNullify rather than
DeallocateAndNullify. (Perhaps you tried compiling your code, and
the misspelling caused the compiler not to know what the function
expects.)

Consider the following test (marked as quotation for linewrap):
>[1] c:\c\junk>cat junk.c
#include <stdio.h>
#include <stdlib.h>

void release(void* *p) {
puts("Was Alive");
free(*p);
*p = NULL;
} /* release */

/* ------------------- */

int main(void) {
int *ptr;

if (ptr = malloc(sizeof *ptr)) release(&ptr);
Maybe:

if (ptr = malloc(sizeof *ptr)) release( &((void *)ptr) );

<snip>

Dec 1 '07 #22
On Sun, 02 Dec 2007 00:27:21 +0530, santosh wrote:
CBFalconer wrote:
>> if (ptr = malloc(sizeof *ptr)) release(&ptr);

Maybe:

if (ptr = malloc(sizeof *ptr)) release( &((void *)ptr) );
That won't compile. ((void *)ptr) is not an lvalue; you cannot take its
address.
Dec 1 '07 #23
Harald van D?k wrote:
On Sun, 02 Dec 2007 00:27:21 +0530, santosh wrote:
>CBFalconer wrote:
>>> if (ptr = malloc(sizeof *ptr)) release(&ptr);

Maybe:

if (ptr = malloc(sizeof *ptr)) release( &((void *)ptr) );

That won't compile. ((void *)ptr) is not an lvalue; you cannot take
its address.
Ah yes. Sorry about that.

Dec 1 '07 #24
CBFalconer wrote:
Keith Thompson wrote:
....
Consider the following test (marked as quotation for linewrap):
>[1] c:\c\junk>cat junk.c
#include <stdio.h>
#include <stdlib.h>

void release(void* *p) {
puts("Was Alive");
free(*p);
*p = NULL;
} /* release */

/* ------------------- */

int main(void) {
int *ptr;

if (ptr = malloc(sizeof *ptr)) release(&ptr);
if (ptr) puts("Alive");
else puts("Dead");

return 0;
} /* main, fcopylns */

[1] c:\c\junk>cc junk.c
junk.c: In function `main':
junk.c:15: warning: suggest parentheses around assignment used as truth value
junk.c:15: warning: passing arg 1 of `release' from incompatible pointer type

[1] c:\c\junk>a
Was Alive
Dead

Now I maintain the error is really a chimera. In release the void*
is never dereferenced, but is simply passed to free (which knows
what to do with it) and is set to NULL before exiting. The
parameter is simply a pointer to a void*.
The argument was a pointer to an int*, which means that even with a
suitable cast to silent the warning, *p==NULL has undefined behavior.
Dec 1 '07 #25
James Kuyper wrote:
Joe Wright wrote:
...
>But int* and void* are compatible.(?)

What made you think that?
Given..

int *ip;

We can do 'ip = malloc(sizeof *ip);

And now,

void *vp = ip;

...is valid. Why do you think not?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Dec 1 '07 #26
Joe Wright wrote:
James Kuyper wrote:
>Joe Wright wrote:
...
>>But int* and void* are compatible.(?)

What made you think that?

Given..

int *ip;

We can do 'ip = malloc(sizeof *ip);

And now,

void *vp = ip;

..is valid. Why do you think not?
What you've just demonstrated is implicit conversion. Many types are
implicitly convertible to other types; section 6.3 is devoted to
describing the many ways in which this can happen. For instance, signed
char is implicitly convertible to long double _Complex. that doesn't
make them compatible.

The term "compatible types" is defined by the C standard in section
6.2.7, with cross-references to several other sections. Follow all of
those cross-references, and you won't find anything that makes "int*"
compatible with "void*".

There are only a few situations where you can access an object using an
lvalue of a one type, if the effective type of the actual object is
different. They are listed in 6.5p7, and the first one is if the lvalue
has " a type compatible with the effective type of the object". Because
int* is not compatible with void*, that case doesn't apply to this code.
Neither do any of the other cases listed in 6.5p7. Therefore, the
behavior of the program is undefined.

It might work as expected, that's one of the possibilities allowed when
the behavior of a program is undefined. On many implementations all
pointers have the same size, alignment, and representation, and on such
implementations this code could work. However, real implementations of C
have different representations for pointers to different types, and even
different sizes. This code will break on any such implementation.
Dec 2 '07 #27
CBFalconer <cb********@yahoo.comwrites:
[...]
Consider the following test (marked as quotation for linewrap):
>[1] c:\c\junk>cat junk.c
#include <stdio.h>
#include <stdlib.h>

void release(void* *p) {
puts("Was Alive");
free(*p);
*p = NULL;
} /* release */

/* ------------------- */

int main(void) {
int *ptr;

if (ptr = malloc(sizeof *ptr)) release(&ptr);
if (ptr) puts("Alive");
else puts("Dead");

return 0;
} /* main, fcopylns */

[1] c:\c\junk>cc junk.c
junk.c: In function `main':
junk.c:15: warning: suggest parentheses around assignment used as truth value
junk.c:15: warning: passing arg 1 of `release' from incompatible pointer type

[1] c:\c\junk>a
Was Alive
Dead

Now I maintain the error is really a chimera. In release the void*
is never dereferenced, but is simply passed to free (which knows
what to do with it) and is set to NULL before exiting. The
parameter is simply a pointer to a void*.
No, the error is a real error.

release() expects an argument of type void**. You give it an argument
of type int**. There is no implicit conversion from int** to void**,
so this is a constraint violation; the compiler is free to reject your
code on that basis, but it chooses instead to issue a warning and
(presumably) generate an implicit conversion anyway.

The language makes certain guarantees about the semantics of
conversions to and from void* (this is separate from the fact that
such conversions can be done implicitly). It makes no such guarantees
about conversions to or from void**, which is just another pointer
type. The conversion from int** to void** (a) is not specified by the
language, and (b) could conceivably lose information.

Now it's not likely that an implementation will actually use different
representations and/or argument passing mechanisms for void** vs.
int**, but it is entirely possible that an implementation could just
reject your code.

[...]

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Looking for software development work in the San Diego area.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Dec 2 '07 #28

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by christopher diggins | last post: by
2 posts views Thread by Devrobcom | last post: by
13 posts views Thread by dimitris67 | last post: by
23 posts views Thread by bluejack | last post: by
5 posts views Thread by Jean-Guillaume Pyraksos | last post: by
78 posts views Thread by Josiah Manson | last post: by
5 posts views Thread by FireHead | last post: by
27 posts views Thread by Terry | last post: by
18 posts views Thread by WaterWalk | last post: by
reply views Thread by leo001 | last post: by
reply views Thread by Anwar ali | last post: by

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.