Casting const void * into void *

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Enrico `Trippo' Porreca

    #1

    Casting const void * into void *

    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(Sta ck *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(S tack *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);
    }

  • Vijay Kumar R Zanvar

    #2
    Re: Casting const void * into void *


    "Enrico `Trippo' Porreca" <trippo@lombard iacom.it> wrote in message news:40BB98B5.1 060300@lombardi acom.it...[color=blue]
    > 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?[/color]

    If you are not modifying the obj parameter, then you could have used:
    void *stack_push(Sta ck *s, void *obj);
    instead. This will also avoid casting to (void*). Unneccessary castings are
    not good.[color=blue]
    >
    > void *stack_push(Sta ck *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?):[/color]

    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"
    [color=blue]
    >
    > void stack_destroy(S tack *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);
    > }
    >[/color]


    Comment

    • Barry Schwarz

      #3
      Re: Casting const void * into void *

      On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
      <trippo@lombard iacom.it> wrote:
      [color=blue]
      >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(Sta ck *s, const void *obj)[/color]

      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.
      [color=blue]
      > {
      > 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?):[/color]

      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?
      [color=blue]
      >
      > void stack_destroy(S tack *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);[/color]

      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.
      [color=blue]
      > }[/color]



      <<Remove the del for email>>

      Comment

      • Stephen Sprunk

        #4
        Re: Casting const void * into void *

        "Barry Schwarz" <schwarzb@deloz .net> wrote in message
        news:c9h4ro$ss5 $1@216.39.135.2 23...[color=blue]
        > On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
        > <trippo@lombard iacom.it> wrote:
        >[color=green]
        > >Given:
        > >
        > > typedef struct Node Node;
        > > struct Node {
        > > void *obj;
        > > Node *next;
        > > };
        > >
        > > typedef struct Stack Stack;
        > > struct Stack {
        > > Node *top;
        > > };[/color][/color]
        ....[color=blue]
        > 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.[/color]

        Why is there only one of them? I see nothing that prevents having more.
        [color=blue]
        > Of course, it's also a little odd to have struct with only one member.[/color]

        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

        Comment

        • Enrico `Trippo' Porreca

          #5
          Re: Casting const void * into void *

          Stephen Sprunk wrote:[color=blue]
          > "Barry Schwarz" <schwarzb@deloz .net> wrote in message
          > news:c9h4ro$ss5 $1@216.39.135.2 23...[color=green]
          >>On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
          >><trippo@lomba rdiacom.it> wrote:
          >>[color=darkred]
          >>>Given:
          >>>
          >>> typedef struct Node Node;
          >>> struct Node {
          >>> void *obj;
          >>> Node *next;
          >>> };
          >>>
          >>> typedef struct Stack Stack;
          >>> struct Stack {
          >>> Node *top;
          >>> };[/color][/color]
          >
          > ...
          >[color=green]
          >>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.[/color][/color]

          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.
          [color=blue][color=green]
          >>Of course, it's also a little odd to have struct with only one member.[/color]
          >
          > 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.[/color]

          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.

          Comment

          • Enrico `Trippo' Porreca

            #6
            Re: Casting const void * into void *

            Barry Schwarz wrote:
            [color=blue]
            > On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca
            > <trippo@lombard iacom.it> wrote:
            >[color=green]
            >>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(Sta ck *s, const void *obj)[/color]
            >
            > 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.[/color]

            I wanted to make obj a const void * maily for documentation purposes and
            for consistency with the Standard C Library functions.
            [color=blue][color=green]
            >> {
            >> 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?):[/color]
            >
            > 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.[/color]

            Ok, I thought deleting the "object" was not allowed by the const modifier.
            [color=blue]
            > 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?[/color]

            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 *?

            Comment

            • Arthur J. O'Dwyer

              #7
              Re: Casting const void * into void *


              On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:[color=blue]
              >
              > Barry Schwarz wrote:[color=green]
              > > On Mon, 31 May 2004 22:42:29 +0200, Enrico `Trippo' Porreca wrote:[color=darkred]
              > >>
              > >> 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(Sta ck *s, const void *obj)[/color]
              > >
              > > 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.[/color]
              >
              > I wanted to make obj a const void * mainly for documentation purposes
              > and for consistency with the Standard C Library functions.[/color]

              But the "documentat ion" 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).
              [color=blue][color=green][color=darkred]
              > >> n->obj = (void *) obj;[/color][/color][/color]
              [color=blue][color=green][color=darkred]
              > >> return (void *) obj; /* successful push */[/color][/color][/color]

              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.
              [color=blue][color=green][color=darkred]
              > >>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?):[/color]
              > >
              > > 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.[/color][/color]

              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.
              [color=blue]
              > Ok, I thought deleting the "object" was not allowed by the const modifier.[/color]

              You're right. Thus, the solution is to remove the useless 'const'.
              [color=blue][color=green]
              > > 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?[/color]
              >
              > 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.[/color]

              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.
              [color=blue]
              > Should I simply stick to void *?[/color]

              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

              Comment

              • Enrico `Trippo' Porreca

                #8
                Re: Casting const void * into void *

                Arthur J. O'Dwyer wrote:[color=blue]
                > On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:
                >[color=green]
                >>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.[/color]
                >
                > 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.
                >[color=green]
                >>Should I simply stick to void *?[/color]
                >
                > Of course. To claim that a pointer whose contents *can* and *will*
                > be modified (no matter by whom) is 'const' is simply poor documentation.[/color]

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

                Comment

                • Michael Wojcik

                  #9
                  Re: Casting const void * into void *


                  In article <Pine.LNX.4.5 8-035.04060110501 40.2589@unix45. andrew.cmu.edu> , "Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> writes:[color=blue]
                  > On Tue, 1 Jun 2004, Enrico `Trippo' Porreca wrote:[color=green]
                  > >
                  > > I wanted to make obj a const void * mainly for documentation purposes
                  > > and for consistency with the Standard C Library functions.[/color]
                  >
                  > But the "documentat ion" is incorrect: you actually *do* want to be
                  > able to modify the target of 'obj' (via 'free', for example).[/color]

                  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 michael.wojcik@ microfocus.com

                  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

                  Comment

                  • Ralmin

                    #10
                    Re: Casting const void * into void *

                    "Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> wrote:
                    [...][color=blue]
                    > 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').[/color]

                    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.


                    Comment

                    • Arthur J. O'Dwyer

                      #11
                      Re: Casting const void * into void *


                      On Wed, 2 Jun 2004, Ralmin wrote:[color=blue]
                      >
                      > "Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> wrote:
                      > [...][color=green]
                      > > 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').[/color]
                      >
                      > What do you mean by "realizing it"?[/color]

                      Seeing it. Making it conspicuous to yourself. Observing
                      it clearly and consciously.
                      [color=blue]
                      > #include <stdlib.h>
                      > int main(void)
                      > {
                      > const int *p = malloc(10 * sizeof *p);
                      > return 0;
                      > }
                      >
                      > Is this not correct C code?[/color]

                      Legal, yes. Correct, no; you forgot to 'free' the result of
                      'malloc' before the end of the program. My point is, you can't
                      generally write something like the above without at some point
                      seeing 'const' and 'malloc' on the same line, and thus realizing
                      "whoops, I'm probably doing something dumb here." [Pathological
                      cases abound, yes, but in practice I don't think you're likely
                      to malloc into a const object without noticing it.]

                      The same kind of argument applies to casts: you can't do a
                      lot of dubious things in C without using a cast, and that cast
                      should make you *realize* that you're doing something dangerous
                      and/or silly.

                      HTH,
                      -Arthur

                      Comment

                      • Richard Tobin

                        #12
                        Re: Casting const void * into void *

                        In article <Pine.LNX.4.5 8-035.04060217094 90.13503@unix47 .andrew.cmu.edu >,
                        Arthur J. O'Dwyer <ajo@nospam.and rew.cmu.edu> wrote:
                        [color=blue]
                        > Legal, yes. Correct, no; you forgot to 'free' the result of
                        >'malloc' before the end of the program.[/color]

                        There is often no point in freeing malloced memory. It's certainly
                        not "incorrect" in general to leave memory unfreed.

                        -- Richard

                        Comment

                        • Arthur J. O'Dwyer

                          #13
                          Re: Casting const void * into void *


                          On Wed, 2 Jun 2004, Richard Tobin wrote:[color=blue]
                          >
                          > Arthur J. O'Dwyer <ajo@nospam.and rew.cmu.edu> wrote:[color=green]
                          > > Legal, yes. Correct, no; you forgot to 'free' the result of
                          > >'malloc' before the end of the program.[/color]
                          >
                          > There is often no point in freeing malloced memory. It's certainly
                          > not "incorrect" in general to leave memory unfreed.[/color]

                          It's a question of definitions, then. If you're willing to accept
                          the memory leak, or you are willing to assume there won't be a
                          memory leak, then that's all right. But in general, if you allocate
                          a block of memory from the implementation and then don't give it
                          back, that's IMO "incorrect. " You ought to free everything you
                          malloc.
                          If your system, like many *nixes, frees all allocated memory as
                          part of program termination, then by all means go ahead and don't
                          free anything yourself. But don't expect anyone else to use your
                          non-portable code. You see the point now?

                          -Arthur

                          Comment

                          • Richard Tobin

                            #14
                            Re: Casting const void * into void *

                            In article <Pine.LNX.4.5 8-035.04060312050 10.3594@unix49. andrew.cmu.edu> ,
                            Arthur J. O'Dwyer <ajo@nospam.and rew.cmu.edu> wrote:
                            [color=blue]
                            >But in general, if you allocate
                            >a block of memory from the implementation and then don't give it
                            >back, that's IMO "incorrect. "[/color]

                            It might be, IYO, "incorrect" , but it's not incorrect.
                            [color=blue]
                            >You ought to free everything you malloc.[/color]

                            This would be the Morality appendix to the C standard?
                            [color=blue]
                            >If your system, like many *nixes, frees all allocated memory as
                            >part of program termination, then by all means go ahead and don't
                            >free anything yourself.[/color]

                            As you must have been aware, I did not suggest never freeing anything.
                            Be more subtle in your hyperbole.

                            Portability is not an absolute. It's a matter of practicalities.
                            Many of my programs won't run on a machine with 64K of memory. Many
                            of them won't run on non-Posix systems. Do I care? Similarly, if you
                            want programs that run on PDAs or embedded devices that don't have an
                            operating system that reclaims memory, feel free to write or port
                            them, but that's not usually my priority. If I judge that it's
                            necessary to avoid memory leakage, I take care to avoid it, and if it
                            isn't I don't worry.
                            [color=blue]
                            >You see the point now?[/color]

                            No. I see a rule-of-thumb turned into a fetish.

                            -- Richard

                            Comment

                            • August Derleth

                              #15
                              Re: Casting const void * into void *

                              On Fri, 04 Jun 2004 00:44:19 +0000, Richard Tobin wrote:
                              [color=blue]
                              > In article <Pine.LNX.4.5 8-035.04060312050 10.3594@unix49. andrew.cmu.edu> ,
                              > Arthur J. O'Dwyer <ajo@nospam.and rew.cmu.edu> wrote:
                              >[color=green]
                              >>But in general, if you allocate
                              >>a block of memory from the implementation and then don't give it
                              >>back, that's IMO "incorrect. "[/color]
                              >
                              > It might be, IYO, "incorrect" , but it's not incorrect.[/color]

                              Not just his opinion. Plenty of others share his view, because plenty of
                              people have been bitten by memory leaks created by lazy programmers like
                              you.
                              [color=blue]
                              >[color=green]
                              >>You ought to free everything you malloc.[/color]
                              >
                              > This would be the Morality appendix to the C standard?[/color]

                              No, it would be common sense. Consider engaging your brain.
                              [color=blue]
                              >[color=green]
                              >>If your system, like many *nixes, frees all allocated memory as
                              >>part of program termination, then by all means go ahead and don't
                              >>free anything yourself.[/color]
                              >
                              > As you must have been aware, I did not suggest never freeing anything.
                              > Be more subtle in your hyperbole.[/color]

                              But his subtlety would be lost on you, and then you'd whine.
                              [color=blue]
                              >
                              > Portability is not an absolute. It's a matter of practicalities.[/color]

                              Bullshit. You can write C code that's portable to all systems which have
                              conforming compilers.
                              [color=blue]
                              > If I judge that it's
                              > necessary to avoid memory leakage, I take care to avoid it,[/color]

                              And you can always know this how... ?
                              [color=blue]
                              >[color=green]
                              >>You see the point now?[/color]
                              >
                              > No. I see a rule-of-thumb turned into a fetish.[/color]

                              Fools see a very different world indeed.


                              --
                              yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
                              To email me, rot13 and convert spelled-out numbers to numeric form.
                              "Makes hackers smile" makes hackers smile.

                              Comment

                              Working...