is const necessary in eg int compar(const void *, const void *)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Richard Heathfield

    #16
    Re: is const necessary in eg int compar(const void *, const void *)

    Richard Tobin said:
    In article <slrngfc37b.e4q .nospam@nospam. invalid>,
    Antoninus Twink <nospam@nospam. invalidwrote:
    >
    >>1) When passing a NULL pointer to variadic functions, you need an
    >>explicit cast, e.g.
    >>s = mystrconcat("he llo", " ", "world", "!", (char *) NULL);
    >
    I'm sure someone will point out how it *can* be done without a cast,
    Mr Twink is wrong on technical grounds and sub-optimal on stylistic
    grounds: firstly, you *don't* need a cast, and secondly, "explicit" is
    redundant.
    but of course a cast is the natural way to do it.
    Yes. I don't think anyone has claimed otherwise.
    >>2) If you have a type that you know is an integer type but is typedef'd
    >>in a system-specific header, then to portably print it you need a cast
    >>to the widest integer type:
    >>
    >>opaque_intege r_type i = somefunction(42 );
    >>printf("The answer is %llu\n", (unsigned long long) i);
    >
    Alternatively the implementor can provide a macro for a format string,
    as C99 does (PRIdMAX etc).
    Yes. But if the type is opaque and not supported by the implementation, the
    cast is in any case unwise. Instead, you should pass the value to the
    opaque type's stream-writing function.

    --
    Richard Heathfield <http://www.cpax.org.uk >
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999

    Comment

    • Nate Eldredge

      #17
      Re: is const necessary in eg int compar(const void *, const void *)

      Richard Heathfield <rjh@see.sig.in validwrites:
      Richard Tobin said:
      >
      >In article <slrngfc37b.e4q .nospam@nospam. invalid>,
      >Antoninus Twink <nospam@nospam. invalidwrote:
      >>
      >>>1) When passing a NULL pointer to variadic functions, you need an
      >>>explicit cast, e.g.
      >>>s = mystrconcat("he llo", " ", "world", "!", (char *) NULL);
      >>
      >I'm sure someone will point out how it *can* be done without a cast,
      >
      Mr Twink is wrong on technical grounds and sub-optimal on stylistic
      grounds: firstly, you *don't* need a cast, and secondly, "explicit" is
      redundant.
      You're thinking of something like

      char *n = NULL;
      s = mystrconcat("he llo", " ", "world", "!", n);

      I assume?
      >but of course a cast is the natural way to do it.
      >
      Yes. I don't think anyone has claimed otherwise.
      >
      >>>2) If you have a type that you know is an integer type but is typedef'd
      >>>in a system-specific header, then to portably print it you need a cast
      >>>to the widest integer type:
      >>>
      >>>opaque_integ er_type i = somefunction(42 );
      >>>printf("Th e answer is %llu\n", (unsigned long long) i);
      >>
      >Alternativel y the implementor can provide a macro for a format string,
      >as C99 does (PRIdMAX etc).
      >
      Yes. But if the type is opaque and not supported by the implementation, the
      cast is in any case unwise. Instead, you should pass the value to the
      opaque type's stream-writing function.
      It's a pleasant world you live in where such things always exist. :)

      Unix, for instance, is rife with integer types that don't come with
      output functions. pid_t, uid_t, half the fields of struct stat, etc.
      So I tend to do

      printf("The file has inode number %ju\n", (uintmax_t)st.s t_ino);

      (st.st_ino has type `ino_t').

      Of course, I can avoid the cast by saying

      uintmax_t inode = st.st_ino;
      printf("The file has inode number %ju\n", inode);



      Comment

      • lovecreatesbeauty@gmail.c0m

        #18
        Re: is const necessary in eg int compar(const void *, const void *)

        On Oct 15, 6:21 pm, James Kuyper <jameskuy...@ve rizon.netwrote:
        lovecreatesbea. ..@gmail.c0m wrote:
        On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.i nvalidwrote:
        lovecreatesbea. ..@gmail.c0m said:
        >If the pointer cannot be dereferenced why worry if the pointed object
        >will be modified?
        The pointer *can* be dereferenced after conversion to the appropriate type.
        For example, look at all the dereferencing going on here:
        >
        Yes, thanks. I got it.
        >
        if(0 == diff)
        {
        diff =
        (left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
        }
        if(0 == diff)
        {
        diff =
        (left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
        }
        >
        why don't you put your code together and create another same selection
        block :)
        >
        If the value of diff was 0 at the first if(), then diff gets
        recalculated, in which case it might be non-0 for the second if(), so
        you can't combine the two blocks into a single if() block.- Hide quoted text -
        >
        Yes, but I don't think the original code is a good piece.


        On Oct 15, 11:16 am, Richard Heathfield <r...@see.sig.i nvalidwrote:
        >
        #include <time.h>
        >
        int cmp_tm(const void *vleft, const void *vright)
        {
        const struct tm *left = vleft;
        const struct tm *right = vright;
        int diff =
        (left->tm_year right->tm_year) - (left->tm_year < right->tm_year);
        if(0 == diff)
        {
        diff =
        (left->tm_mon right->tm_mon) - (left->tm_mon < right->tm_mon);
        }
        if(0 == diff)
        {
        diff =
        (left->tm_mday right->tm_mday) - (left->tm_mday < right->tm_mday);
        }
        /* hour, min, sec similarly */
        >
        return diff;
        >
        }
        #include <time.h>

        int cmp_tm(const void *v1, const void *v2)
        {
        const struct tm *t1 = v1;
        const struct tm *t2 = v2;
        int diff_y, diff_m, diff_d;

        diff_y = t1->tm_year != t2->tm_year;
        diff_m = t1->tm_mon != t2->tm_mon;
        diff_d = t1->tm_mday != t2->tm_mday;

        if (!diff_y && !diff_m){
        /* usage of diff_d; */
        }

        /* hour, min, sec similarly */

        return diff_d; /*diff in sec maybe*/
        }

        Comment

        • Ian Collins

          #19
          Re: is const necessary in eg int compar(const void *, const void*)

          lovecreatesbeau ty@gmail.c0m wrote:
          >
          is it better to use this simple line:
          d[0] = t1->tm_year - t2->tm_year;
          >
          instead of Richard Heathfield's:
          diff = (left->tm_year right->tm_year) - (left->tm_year < right-
          >tm_year);
          >
          Richard's technique is intended to remove the risk of integer over
          (under?) flow.

          --
          Ian Collins

          Comment

          • Richard Heathfield

            #20
            Re: is const necessary in eg int compar(const void *, const void *)

            jaysome said:
            On Wed, 15 Oct 2008 08:45:29 +0000, Richard Heathfield
            <rjh@see.sig.in validwrote:
            >
            <snip>
            >>I'm of the opinion that it's always possible, and usually preferable, to
            >>avoid casting.
            >
            If p is of any type other than void *, can (and should) this cast be
            avoided?
            >
            printf("p = %p\n", (void*)p);
            Can - yes, by using a temp. Should? That's a question of style.

            --
            Richard Heathfield <http://www.cpax.org.uk >
            Email: -http://www. +rjh@
            Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
            "Usenet is a strange place" - dmr 29 July 1999

            Comment

            • CBFalconer

              #21
              Re: is const necessary in eg int compar(const void *, const void *)

              jaysome wrote:
              >
              .... snip ...
              >
              If p is of any type other than void *, can (and should) this cast
              be avoided?
              >
              printf("p = %p\n", (void*)p);
              The variadic functions, in particular printf and clones, are
              glaring examples of exceptions to the general rule "casts are
              errors". The reason is that the only type information such
              functions have is the construct of the format string, which is not
              generally known at compile time (the format string may be a
              variable).

              In your example, above, the %p has specified that the functions is
              receiving a void* parameter. So, if p is not of this type, you
              have to convert it with a cast. A good compiler will at least tell
              you if you are making an illegal cast, such as casting an integer
              to a void*.

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

              Comment

              • Ben Bacarisse

                #22
                Re: is const necessary in eg int compar(const void *, const void *)

                CBFalconer <cbfalconer@yah oo.comwrites:

                <snip>
                ... A good compiler will at least tell
                you if you are making an illegal cast, such as casting an integer
                to a void*.
                What is "illegal" about it? The conversion is implementation defined,
                but illegal seems way too strong a word.

                --
                Ben.

                Comment

                • vippstar@gmail.com

                  #23
                  Re: is const necessary in eg int compar(const void *, const void *)

                  On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                  CBFalconer <cbfalco...@yah oo.comwrites:
                  >
                  <snip>
                  >
                  ... A good compiler will at least tell
                  you if you are making an illegal cast, such as casting an integer
                  to a void*.
                  >
                  What is "illegal" about it? The conversion is implementation defined,
                  but illegal seems way too strong a word.
                  The conversion is implementation defined, and one of the possible
                  behaviors is undefined behavior.
                  If something is UB on an imaginary implementation it's a good enough
                  reason for me to avoid that 'something'.
                  Chuck could've just been more clear by using a term defined in the
                  standard.

                  Comment

                  • Nick Keighley

                    #24
                    Re: is const necessary in eg int compar(const void *, const void *)

                    On 27 Oct, 21:24, vipps...@gmail. com wrote:
                    On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                    CBFalconer <cbfalco...@yah oo.comwrites:
                    ...  A good compiler will at least tell
                    you if you are making an illegal cast, such as casting an integer
                    to a void*.
                    >
                    What is "illegal" about it?  The conversion is implementation defined,
                    but illegal seems way too strong a word.
                    >
                    The conversion is implementation defined, and one of the possible
                    behaviors is undefined behavior.
                    I didn't think that was so. I thought Implementation Defined
                    actually had to be defined by the implementation. And that the
                    standard usually (nearly always?) gave a narrow range of
                    possibilities.

                    <find standard>

                    Para 3.3.4 "Cast Operators"
                    [...]
                    "A pointer may be converted to an integral type. The size of
                    integer required and the result is implementaion-defined. If
                    the space provided is not long enough, the behaviour is
                    undefined"

                    Seems to be having it both ways...

                    The Rationale has this to say:

                    "Nothing portable can be said about casting integers to pointers,
                    or vice versa, since the two are now incommensurate. "

                    which sounds very like UB to me...

                    If something is UB on an imaginary implementation it's a good enough
                    reason for me to avoid that 'something'.
                    Chuck could've just been more clear by using a term defined in the
                    standard.

                    --
                    Nick Keighley

                    1,3,7-trimethylxanthi ne -- a basic ingredient in quality software.

                    Comment

                    • jameskuyper

                      #25
                      Re: is const necessary in eg int compar(const void *, const void *)

                      Nick Keighley wrote:
                      On 27 Oct, 21:24, vipps...@gmail. com wrote:
                      On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                      CBFalconer <cbfalco...@yah oo.comwrites:
                      >
                      ... �A good compiler will at least tell
                      you if you are making an illegal cast, such as casting an integer
                      to a void*.
                      What is "illegal" about it? �The conversion is implementationd efined,
                      but illegal seems way too strong a word.
                      The conversion is implementation defined, and one of the possible
                      behaviors is undefined behavior.
                      >
                      I didn't think that was so. I thought Implementation Defined
                      actually had to be defined by the implementation. And that the
                      standard usually (nearly always?) gave a narrow range of
                      possibilities.
                      It does, sort of:

                      6.3.2.3p5: "An integer may be converted to any pointer type. Except as
                      previously specified, the result is implementation-defined, might not
                      be correctly aligned, might not point to an entity of the referenced
                      type, and might be a trap representation. "

                      For void*, the possibility of incorrect alignment is not a problem.
                      Its not even possible for the resulting pointer to point to an entity
                      of the referenced type, so that's not an issue, either. The problem is
                      the last item on the list of possibilities. There's no problem if the
                      implementation-defined behavior does not include trap representations ,
                      but portable code cannot make any such assumption. The behavior is
                      undefined if you store the result of such a conversion in an object.

                      It is an oddity of the standard that the possible result of a
                      conversion, which is a value, is referred to as a "representation ",
                      something that can only be stored in an object. All the nasty things
                      that the standard says explicitly about trap representations apply
                      only if you try to store them in an object using an lvalue of pointer
                      type, or if you use an object that has had such had such a
                      representation created in it by other means. This would seem to imply
                      that it should be perfectly safe to make use of a trap representation
                      returned by a conversion, so long as you don't use it any way that
                      would otherwise result in it being stored in an object. However, I
                      strongly suspect that you can produce an argument that it is
                      implicitly undefined behavior to do anything with such a trap
                      representation, due to lack of an explicit definition of the behavior.

                      Comment

                      • Tim Rentsch

                        #26
                        Re: is const necessary in eg int compar(const void *, const void *)

                        jameskuyper <jameskuyper@ve rizon.netwrites :
                        Nick Keighley wrote:
                        On 27 Oct, 21:24, vipps...@gmail. com wrote:
                        On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                        CBFalconer <cbfalco...@yah oo.comwrites:
                        ... =EF=BF=BDA good compiler will at least tell
                        you if you are making an illegal cast, such as casting an integer
                        to a void*.
                        >
                        What is "illegal" about it? =EF=BF=BDThe conversion is implementation=
                        defined,
                        but illegal seems way too strong a word.
                        >
                        The conversion is implementation defined, and one of the possible
                        behaviors is undefined behavior.
                        I didn't think that was so. I thought Implementation Defined
                        actually had to be defined by the implementation. And that the
                        standard usually (nearly always?) gave a narrow range of
                        possibilities.
                        >
                        It does, sort of:
                        >
                        6.3.2.3p5: "An integer may be converted to any pointer type. Except as
                        previously specified, the result is implementation-defined, might not
                        be correctly aligned, might not point to an entity of the referenced
                        type, and might be a trap representation. "
                        >
                        For void*, the possibility of incorrect alignment is not a problem.
                        Its not even possible for the resulting pointer to point to an entity
                        of the referenced type, so that's not an issue, either. The problem is
                        the last item on the list of possibilities. There's no problem if the
                        implementation-defined behavior does not include trap representations ,
                        but portable code cannot make any such assumption. The behavior is
                        undefined if you store the result of such a conversion in an object.
                        >
                        It is an oddity of the standard that the possible result of a
                        conversion, which is a value, is referred to as a "representation ",
                        something that can only be stored in an object. All the nasty things
                        that the standard says explicitly about trap representations apply
                        only if you try to store them in an object using an lvalue of pointer
                        type, or if you use an object that has had such had such a
                        representation created in it by other means. This would seem to imply
                        that it should be perfectly safe to make use of a trap representation
                        returned by a conversion, so long as you don't use it any way that
                        would otherwise result in it being stored in an object. However, I
                        strongly suspect that you can produce an argument that it is
                        implicitly undefined behavior to do anything with such a trap
                        representation, due to lack of an explicit definition of the behavior.
                        Yes; it's a simple argument.

                        Any attempt to use the value of a trap representation (using the
                        type where it's a trap representation) certainly should be
                        undefined behavior, since trap representations don't represent a
                        value of that type. The Standard is quite clear about this:
                        the absence of definition means undefined behavior just the same
                        as if it were labelled undefined behavior.

                        Arguably a trap representation evaluated as a (void) expression
                        doesn't have its value used, so this might be okay. But anywhere
                        else a trap representation occurs in a value context, including
                        further conversion, needs to use the value and hence is undefined
                        behavior.

                        Comment

                        • CBFalconer

                          #27
                          Re: is const necessary in eg int compar(const void *, const void *)

                          Tim Rentsch wrote:
                          jameskuyper <jameskuyper@ve rizon.netwrites :
                          >Nick Keighley wrote:
                          >>
                          .... snip ...
                          >>
                          >>I didn't think that was so. I thought Implementation Defined
                          >>actually had to be defined by the implementation. And that the
                          >>standard usually (nearly always?) gave a narrow range of
                          >>possibilities .
                          >>
                          >It does, sort of:
                          >
                          .... snip ...
                          >
                          Yes; it's a simple argument.
                          The point is that 'implementation defined' is not universal. One
                          implementation may define it one way, another in some other
                          manner. So you can't count on code that invokes that.

                          Thus using it is not portable C. And portable C, as defined by the
                          C standard, is the subject of discussion on c.l.c. If you go to a
                          newsgroup that deals with _your_ system, it will be topical.

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

                          Comment

                          • Tim Rentsch

                            #28
                            Re: is const necessary in eg int compar(const void *, const void *)

                            Eric Sosman <Eric.Sosman@su n.comwrites:
                            Richard Heathfield wrote:
                            lovecreatesbeau ty@gmail.c0m said:
                            Is the keyword const necessary in the comparison function in qsort and
                            bsearch?
                            >
                            int (*compar)(const void *, const void *)
                            Yes.
                            >
                            Well, either "yes" or "no" depending on what "necessary" means.
                            >
                            Yes, it is "necessary, " because qsort() and bsearch() specify
                            `const' as part of the signature of the comparison function they
                            call. If you try to pass a pointer to a function with a different
                            signature, the compiler will complain and may reject your code. So
                            `const' is "necessary" if you want to be sure the code compiles.
                            [...]
                            I'm sure a lot of readers know this but for those that don't...

                            In C the correct term is "type" and not "signature" . The term
                            "signature" comes from the programming language Russell, where
                            it's important to use a word different from "type" because "type"
                            means something different in Russell (related to the common
                            meaning of type, but still significantly different).

                            It's common in programming language circles to use the word
                            "signature" rather than "type" (especially when talking about
                            functions, for some reason), even when "type" is adequate and also
                            more accurate in the sense that it reflects the terminology used
                            by the programming language under discussion. I don't know why
                            people do this; my guess is because it sounds like it's more
                            precise or perhaps more grounded in some formal theoretical
                            framework. Neither of those is true, by the way.

                            There is an important sense in which "signature" is inappropriate
                            for C, in that functions in Russell (with signatures) are more
                            powerful than functions in C (with types). In particular, a
                            function in Russell admits parameters that are abstract data types
                            (what Russell calls a "type"); thus a function in Russell is like
                            a function template in C++, except that unlike templates in C++ a
                            function in Russell doesn't need to be instantiated to be used
                            with different type parameters -- in Russell abstract data types
                            are values and can be used just like ordinary values (such as int)
                            can. C doesn't admit abstract data types as values or parameters.

                            So if you're talking to someone about C and the term "signature"
                            comes up, it might be a good idea to ask "Do you mean type, or
                            are you talking about a different language?"

                            None of the above is intended as any kind of comment on Mr. Sosman,
                            who in my experience is both a gracious guy and a generally smart
                            fellow.

                            Comment

                            • Tim Rentsch

                              #29
                              Re: is const necessary in eg int compar(const void *, const void *)

                              CBFalconer <cbfalconer@yah oo.comwrites:
                              Tim Rentsch wrote:
                              jameskuyper <jameskuyper@ve rizon.netwrites :
                              Nick Keighley wrote:
                              >
                              ... snip ...
                              >
                              >I didn't think that was so. I thought Implementation Defined
                              >actually had to be defined by the implementation. And that the
                              >standard usually (nearly always?) gave a narrow range of
                              >possibilitie s.
                              >
                              It does, sort of:
                              ... snip ...

                              Yes; it's a simple argument.
                              >
                              The point is that 'implementation defined' is not universal. One
                              implementation may define it one way, another in some other
                              manner. So you can't count on code that invokes that.
                              >
                              Thus using it is not portable C. And portable C, as defined by the
                              C standard, is the subject of discussion on c.l.c. If you go to a
                              newsgroup that deals with _your_ system, it will be topical.
                              If you read my posting (repeated below) again, I think you'll see
                              that it's a response to a sub-comment made by James Kuyper about
                              trap representations , and doesn't have anything to do with
                              implementation-defined behavior. I left in the earlier material,
                              about implementation-defined behavior, to help provide context;
                              I'm sorry if it being left in confused you.


                              ORIGINAL POSTING:

                              jameskuyper <jameskuyper@ve rizon.netwrites :
                              Nick Keighley wrote:
                              On 27 Oct, 21:24, vipps...@gmail. com wrote:
                              On Oct 26, 2:16 am, Ben Bacarisse <ben.use...@bsb .me.ukwrote:
                              CBFalconer <cbfalco...@yah oo.comwrites:
                              ... =EF=BF=BDA good compiler will at least tell
                              you if you are making an illegal cast, such as casting an integer
                              to a void*.
                              >
                              What is "illegal" about it? =EF=BF=BDThe conversion is implementation=
                              defined,
                              but illegal seems way too strong a word.
                              >
                              The conversion is implementation defined, and one of the possible
                              behaviors is undefined behavior.
                              I didn't think that was so. I thought Implementation Defined
                              actually had to be defined by the implementation. And that the
                              standard usually (nearly always?) gave a narrow range of
                              possibilities.
                              >
                              It does, sort of:
                              >
                              6.3.2.3p5: "An integer may be converted to any pointer type. Except as
                              previously specified, the result is implementation-defined, might not
                              be correctly aligned, might not point to an entity of the referenced
                              type, and might be a trap representation. "
                              >
                              For void*, the possibility of incorrect alignment is not a problem.
                              Its not even possible for the resulting pointer to point to an entity
                              of the referenced type, so that's not an issue, either. The problem is
                              the last item on the list of possibilities. There's no problem if the
                              implementation-defined behavior does not include trap representations ,
                              but portable code cannot make any such assumption. The behavior is
                              undefined if you store the result of such a conversion in an object.
                              >
                              It is an oddity of the standard that the possible result of a
                              conversion, which is a value, is referred to as a "representation ",
                              something that can only be stored in an object. All the nasty things
                              that the standard says explicitly about trap representations apply
                              only if you try to store them in an object using an lvalue of pointer
                              type, or if you use an object that has had such had such a
                              representation created in it by other means. This would seem to imply
                              that it should be perfectly safe to make use of a trap representation
                              returned by a conversion, so long as you don't use it any way that
                              would otherwise result in it being stored in an object. However, I
                              strongly suspect that you can produce an argument that it is
                              implicitly undefined behavior to do anything with such a trap
                              representation, due to lack of an explicit definition of the behavior.
                              Yes; it's a simple argument.

                              Any attempt to use the value of a trap representation (using the
                              type where it's a trap representation) certainly should be
                              undefined behavior, since trap representations don't represent a
                              value of that type. The Standard is quite clear about this:
                              the absence of definition means undefined behavior just the same
                              as if it were labelled undefined behavior.

                              Arguably a trap representation evaluated as a (void) expression
                              doesn't have its value used, so this might be okay. But anywhere
                              else a trap representation occurs in a value context, including
                              further conversion, needs to use the value and hence is undefined
                              behavior.

                              Comment

                              Working...