Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Casting const void * into void *

Reply
Thread Tools

Casting const void * into void *

 
 
Enrico `Trippo' Porreca
Guest
Posts: n/a
 
      05-31-2004
Given:

typedef struct Node Node;
struct Node {
void *obj;
Node *next;
};

typedef struct Stack Stack;
struct Stack {
Node *top;
};

....is the following a conforming C function (I am particularly worried
about the casts), since I'm not modifying the obj parameter?

void *stack_push(Stack *s, const void *obj)
{
Node *n;

assert(s != NULL);
assert(obj != NULL);
n = malloc(sizeof *n);
if (n == NULL)
return NULL; /* push failed */
n->obj = (void *) obj;
n->next = s->top;
s->top = n;
return (void *) obj; /* successful push */
}

I can't make the obj field of struct Node a const void *, since the user
will probably free it by the "destructor" (I can't free a const void *,
right?):

void stack_destroy(Stack *s, void (*destroy)(void *))
{
Node *n, *tmp;

assert(s != NULL);
n = s->top;
while (n != NULL) {
tmp = n->next;
if (destroy != NULL)
destroy(n->obj); /* probably destroy == free */
free(n);
n = tmp;
}
free(s);
}

 
Reply With Quote
 
 
 
 
Vijay Kumar R Zanvar
Guest
Posts: n/a
 
      06-01-2004

"Enrico `Trippo' Porreca" <(E-Mail Removed)> wrote in message news:(E-Mail Removed)...
> Given:
>
> typedef struct Node Node;
> struct Node {
> void *obj;
> Node *next;
> };
>
> typedef struct Stack Stack;
> struct Stack {
> Node *top;
> };
>
> ...is the following a conforming C function (I am particularly worried
> about the casts), since I'm not modifying the obj parameter?


If you are not modifying the obj parameter, then you could have used:
void *stack_push(Stack *s, void *obj);
instead. This will also avoid casting to (void*). Unneccessary castings are
not good.
>
> void *stack_push(Stack *s, const void *obj)
> {
> Node *n;
>
> assert(s != NULL);
> assert(obj != NULL);
> n = malloc(sizeof *n);
> if (n == NULL)
> return NULL; /* push failed */
> n->obj = (void *) obj;
> n->next = s->top;
> s->top = n;
> return (void *) obj; /* successful push */
> }
>
> I can't make the obj field of struct Node a const void *, since the user
> will probably free it by the "destructor" (I can't free a const void *,
> right?):


For,
const void *obj;
the statement,
free ( n -> obj );
would generate the following message:

"warning: passing arg 1 of `free' discards qualifiers from pointer target type"

>
> void stack_destroy(Stack *s, void (*destroy)(void *))
> {
> Node *n, *tmp;
>
> assert(s != NULL);
> n = s->top;
> while (n != NULL) {
> tmp = n->next;
> if (destroy != NULL)
> destroy(n->obj); /* probably destroy == free */
> free(n);
> n = tmp;
> }
> free(s);
> }
>



 
Reply With Quote
 
 
 
 
Barry Schwarz
Guest
Posts: n/a
 
      06-01-2004
On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
<(E-Mail Removed)> wrote:

>Given:
>
> typedef struct Node Node;
> struct Node {
> void *obj;
> Node *next;
> };
>
> typedef struct Stack Stack;
> struct Stack {
> Node *top;
> };
>
>...is the following a conforming C function (I am particularly worried
>about the casts), since I'm not modifying the obj parameter?
>
> void *stack_push(Stack *s, const void *obj)


This says obj is a pointer to a const void. Since there is no way to
modify a void, the only purpose served by the const is to assure the
callers of the function that you really won't alter the data obj
points to.

> {
> Node *n;
>
> assert(s != NULL);
> assert(obj != NULL);
> n = malloc(sizeof *n);
> if (n == NULL)
> return NULL; /* push failed */
> n->obj = (void *) obj;
> n->next = s->top;
> s->top = n;
> return (void *) obj; /* successful push */
> }
>
>I can't make the obj field of struct Node a const void *, since the user
>will probably free it by the "destructor" (I can't free a const void *,
>right?):


What makes you think not? Free doesn't alter to contents of the
"object" pointed to. It deletes it from existence which is completely
different. You may have to cast the const void* to a simple void* to
avoid the diagnostic about incompatible const attributes.

The real question remains why would you want to? Is it your intent
that no function in your program ever modify the contents of whatever
n->obj points to once it has been added to the list?

>
> void stack_destroy(Stack *s, void (*destroy)(void *))
> {
> Node *n, *tmp;
>
> assert(s != NULL);
> n = s->top;
> while (n != NULL) {
> tmp = n->next;
> if (destroy != NULL)
> destroy(n->obj); /* probably destroy == free */
> free(n);
> n = tmp;
> }
> free(s);


It would be a little odd for s to point to an allocated Stack since
the struct is so small and there is only one of them. Of course, it's
also a little odd to have struct with only one member.

> }




<<Remove the del for email>>
 
Reply With Quote
 
Stephen Sprunk
Guest
Posts: n/a
 
      06-01-2004
"Barry Schwarz" <(E-Mail Removed)> wrote in message
news:c9h4ro$ss5$1@216.39.135.223...
> On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
> <(E-Mail Removed)> wrote:
>
> >Given:
> >
> > typedef struct Node Node;
> > struct Node {
> > void *obj;
> > Node *next;
> > };
> >
> > typedef struct Stack Stack;
> > struct Stack {
> > Node *top;
> > };

....
> It would be a little odd for s to point to an allocated Stack since
> the struct is so small and there is only one of them.


Why is there only one of them? I see nothing that prevents having more.

> Of course, it's also a little odd to have struct with only one member.


Provided the implementation was suitably abstracted, it enables him to add
other members to struct Stack later without callers needing to know. It
also keeps types consistent with, say, a doubly-linked list, which needs to
be a struct to keep track of both ends.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

 
Reply With Quote
 
Enrico `Trippo' Porreca
Guest
Posts: n/a
 
      06-01-2004
Stephen Sprunk wrote:
> "Barry Schwarz" <(E-Mail Removed)> wrote in message
> news:c9h4ro$ss5$1@216.39.135.223...
>>On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
>><(E-Mail Removed)> wrote:
>>
>>>Given:
>>>
>>> typedef struct Node Node;
>>> struct Node {
>>> void *obj;
>>> Node *next;
>>> };
>>>
>>> typedef struct Stack Stack;
>>> struct Stack {
>>> Node *top;
>>> };

>
> ...
>
>>It would be a little odd for s to point to an allocated Stack since
>>the struct is so small and there is only one of them.


I'm not allowing the user to have an automatic (or static) struct Stack,
since the struct definition is hidden in the implementation file. The
"stack.h" header contains just the typedef. And the user can always
create an arbitrary number of Stacks.

>>Of course, it's also a little odd to have struct with only one member.

>
> Provided the implementation was suitably abstracted, it enables him to add
> other members to struct Stack later without callers needing to know. It
> also keeps types consistent with, say, a doubly-linked list, which needs to
> be a struct to keep track of both ends.


In fact I'm also writing a queue (implemented with a struct containing
two pointers) and some more complicated data structures. Consistency
(and expandibility) was exactly what I had in mind while writing my code.

 
Reply With Quote
 
Enrico `Trippo' Porreca
Guest
Posts: n/a
 
      06-01-2004
Barry Schwarz wrote:

> On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
> <(E-Mail Removed)> wrote:
>
>>Given:
>>
>> typedef struct Node Node;
>> struct Node {
>> void *obj;
>> Node *next;
>> };
>>
>> typedef struct Stack Stack;
>> struct Stack {
>> Node *top;
>> };
>>
>>...is the following a conforming C function (I am particularly worried
>>about the casts), since I'm not modifying the obj parameter?
>>
>> void *stack_push(Stack *s, const void *obj)

>
> This says obj is a pointer to a const void. Since there is no way to
> modify a void, the only purpose served by the const is to assure the
> callers of the function that you really won't alter the data obj
> points to.


I wanted to make obj a const void * maily for documentation purposes and
for consistency with the Standard C Library functions.

>> {
>> Node *n;
>>
>> assert(s != NULL);
>> assert(obj != NULL);
>> n = malloc(sizeof *n);
>> if (n == NULL)
>> return NULL; /* push failed */
>> n->obj = (void *) obj;
>> n->next = s->top;
>> s->top = n;
>> return (void *) obj; /* successful push */
>> }
>>
>>I can't make the obj field of struct Node a const void *, since the user
>>will probably free it by the "destructor" (I can't free a const void *,
>>right?):

>
> What makes you think not? Free doesn't alter to contents of the
> "object" pointed to. It deletes it from existence which is completely
> different.


Ok, I thought deleting the "object" was not allowed by the const modifier.

> The real question remains why would you want to? Is it your intent
> that no function in your program ever modify the contents of whatever
> n->obj points to once it has been added to the list?


I want the user to be able to modify the contents of n->obj outside my
stack management functions if he wants, but I also want to document the
fact that no function in my library will ever do.

Should I simply stick to void *?

 
Reply With Quote
 
Arthur J. O'Dwyer
Guest
Posts: n/a
 
      06-01-2004

On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:
>
> Barry Schwarz wrote:
> > On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca wrote:
> >>
> >> typedef struct Node Node;
> >> struct Node {
> >> void *obj;
> >> Node *next;
> >> };
> >>
> >> typedef struct Stack Stack;
> >> struct Stack {
> >> Node *top;
> >> };
> >>
> >>...is the following a conforming C function (I am particularly worried
> >>about the casts), since I'm not modifying the obj parameter?
> >>
> >> void *stack_push(Stack *s, const void *obj)

> >
> > This says obj is a pointer to a const void. Since there is no way to
> > modify a void, the only purpose served by the const is to assure the
> > callers of the function that you really won't alter the data obj
> > points to.

>
> I wanted to make obj a const void * mainly for documentation purposes
> and for consistency with the Standard C Library functions.


But the "documentation" is incorrect: you actually *do* want to be
able to modify the target of 'obj' (via 'free', for example). And
the standard C library is irrelevant, as far as I can tell (except
insofar as 'free' is part of it, which just supports the no-'const'
case).

> >> n->obj = (void *) obj;


> >> return (void *) obj; /* successful push */


If you silently cast away the constness of a parameter declared as
'const', you are doing your client a greater disservice than simply
declaring it non-const in the first place. Any casts in your code
should be viewed with *EXTREME* caution and distrust.

> >>I can't make the obj field of struct Node a const void *, since the user
> >>will probably free it by the "destructor" (I can't free a const void *,
> >>right?):

> >
> > What makes you think not? Free doesn't alter to contents of the
> > "object" pointed to. It deletes it from existence which is completely
> > different.


Wrong. 'free' deletes the object, and at that point it's allowed to
do *anything* with the freed block, including writing over its contents.
So a 'free' written in standard C obviously needs to take a non-'const'
parameter.
More importantly, there's no reason to free a 'const' object in C,
since the only thing you're allowed to free is the result of a 'malloc',
and you can't put the result of a function call into a 'const' without
realizing it (and thus realizing that you need to remove the 'const').
Finally, you cannot legally 'free' a const pointer because the Standard
says so. 'free' is defined to take a non-const pointer to void, and if
you pass it a 'const' pointer to void, you're breaking the rules.
Undefined behavior may well ensue.

> Ok, I thought deleting the "object" was not allowed by the const modifier.


You're right. Thus, the solution is to remove the useless 'const'.

> > The real question remains why would you want to? Is it your intent
> > that no function in your program ever modify the contents of whatever
> > n->obj points to once it has been added to the list?

>
> I want the user to be able to modify the contents of n->obj outside my
> stack management functions if he wants, but I also want to document the
> fact that no function in my library will ever do.


So document it. The simplest way would be to write, "No function
in my library will ever change the target of the pointer 'obj'." You
can get fancier if you want.

> Should I simply stick to void *?


Of course. To claim that a pointer whose contents *can* and *will*
be modified (no matter by whom) is 'const' is simply poor documentation.

-Arthur
 
Reply With Quote
 
Enrico `Trippo' Porreca
Guest
Posts: n/a
 
      06-01-2004
Arthur J. O'Dwyer wrote:
> On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:
>
>>I want the user to be able to modify the contents of n->obj outside my
>>stack management functions if he wants, but I also want to document the
>>fact that no function in my library will ever do.

>
> So document it. The simplest way would be to write, "No function
> in my library will ever change the target of the pointer 'obj'." You
> can get fancier if you want.
>
>>Should I simply stick to void *?

>
> Of course. To claim that a pointer whose contents *can* and *will*
> be modified (no matter by whom) is 'const' is simply poor documentation.


So I guess it'll be void * (as in my first version ).

 
Reply With Quote
 
Michael Wojcik
Guest
Posts: n/a
 
      06-02-2004

In article <(E-Mail Removed)>, "Arthur J. O'Dwyer" <(E-Mail Removed)> writes:
> On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:
> >
> > I wanted to make obj a const void * mainly for documentation purposes
> > and for consistency with the Standard C Library functions.

>
> But the "documentation" is incorrect: you actually *do* want to be
> able to modify the target of 'obj' (via 'free', for example).


I'll agree with Arthur here. stack_push itself does not modify obj,
which suggests that obj ought to be declared as const void * (so that
const data could be added to the stack). However, the suggestion is
misleading, because stack_push puts obj in the line of free's fire,
so to speak. In effect it schedules (or may schedule) obj for later
freeing, which is an operation with side effects on obj.

So while "parameter P may be const if function does not have side
effects that affect P" is normally a good rule of thumb, it's not the
whole story for const-correctness. If the function exposes P to other
functions, that expands the scope in which P's constness must be
considered. Fortunately, in this case C's type system (and a
cooperating implementation) was sufficient to notify you of that: try
to make P const, and at some point you'll need a cast (because of
that eventual call to free).

--
Michael Wojcik http://www.velocityreviews.com/forums/(E-Mail Removed)

It's like being shot at in an airport with all those guys running
around throwing hand grenades. Certain people function better with
hand grenades coming from all sides than other people do when the
hand grenades are only coming from inside out. -- Dick Selcer
 
Reply With Quote
 
Ralmin
Guest
Posts: n/a
 
      06-02-2004
"Arthur J. O'Dwyer" <(E-Mail Removed)> wrote:
[...]
> More importantly, there's no reason to free a 'const'
> object in C, since the only thing you're allowed to free
> is the result of a 'malloc', and you can't put the result
> of a function call into a 'const' without realizing it
> (and thus realizing that you need to remove the 'const').


What do you mean by "realizing it"?

#include <stdlib.h>
int main(void)
{
const int *p = malloc(10 * sizeof *p);
return 0;
}

Is this not correct C code?

--
Simon.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
is const necessary in eg int compar(const void *, const void *) lovecreatesbeauty@gmail.c0m C Programming 26 11-10-2008 09:47 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM
Casting int'** to 'const int * const * const' dosn't work, why? Jonas.Holmsten@gmail.com C Programming 11 07-01-2007 06:16 PM
Casting void * to void ** ? Twister C Programming 31 05-04-2006 01:21 AM
[Slightly OT] Casting non-void function results to void in modern compilers. David M. Wilson C Programming 8 01-07-2004 07:32 AM



Advertisments