implicit type conversions

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

    #1

    implicit type conversions

    Let me see if I got this :)
    1. I know the rules for type conversions in arithmetic expressions
    2. I know that an implicit type conversion is done at assignment, so
    float x = 1.23;
    int t = (int) x;
    is equivalent to
    int t = x;
    (could the latter produce a warning on some complier?)
    3. I know that implicit conversions take place with function arguments, but
    am a bit shaky here. I suppose that passing a char to a function accepting
    int or long will always work, and those sort of conversions seem to make
    sense. But what sort of things won't work here? For example, the FAQ says
    that the NULL pointer *must* be cast to the appropriate type when sent to a
    function as an argument (so, for example, time(NULL) is incorrect, and
    time( (time_t *) NULL) is correct?), which seems to indicate that
    conversions from (void *) to (some_type *) in function argument lists need
    not be (isn't) implicit. If someone would clarify this, I'd be most grateful
    (like which sort of things cause warnings, which need be cast and the like).

    Thank you.


  • Eric Sosman

    #2
    Re: implicit type conversions

    buda wrote:[color=blue]
    > Let me see if I got this :)
    > 1. I know the rules for type conversions in arithmetic expressions
    > 2. I know that an implicit type conversion is done at assignment, so
    > float x = 1.23;
    > int t = (int) x;
    > is equivalent to
    > int t = x;
    > (could the latter produce a warning on some complier?)[/color]

    Yes. The Standard requires diagnostics for some violations,
    but does not forbid diagnostics even when no violation has been
    detected. Years ago, I used a compiler that complained about

    float f = 0.0;

    .... because of the potential "loss of precision" involved in
    shortening the `double' to `float'.

    Sometimes the extra diagnostics are helpful, and sometimes
    they are merely noise.
    [color=blue]
    > 3. I know that implicit conversions take place with function arguments, but
    > am a bit shaky here. I suppose that passing a char to a function accepting
    > int or long will always work, and those sort of conversions seem to make
    > sense. But what sort of things won't work here? For example, the FAQ says
    > that the NULL pointer *must* be cast to the appropriate type when sent to a
    > function as an argument (so, for example, time(NULL) is incorrect, and
    > time( (time_t *) NULL) is correct?), which seems to indicate that
    > conversions from (void *) to (some_type *) in function argument lists need
    > not be (isn't) implicit. If someone would clarify this, I'd be most grateful
    > (like which sort of things cause warnings, which need be cast and the like).[/color]

    If the function has a prototype that describes the types of
    all its formal parameters, the argument values you supply will be
    converted to the types the function expects. For example, if you
    have #include'd <time.h>, the time() function has been declared
    as taking one argument of type `time_t*', so the compiler has the
    information it needs to convert a plain `NULL' to `(time_t*)NULL' .
    In this situation, time(NULL) and time( (time_t*)NULL ) are
    equivalent.

    However, there are three situations where the compiler lacks
    the information it would need to do such conversions automatically:

    - If the function has not been declared prior to its use,
    the compiler knows nothing about what parameters it expects.

    - If the function has been declared but without a prototype
    describing the arguments (e.g., `double trouble();'), the
    compiler once again has no knowledge of what's expected.

    - If the function has been declared with a prototype but is
    a "variadic" function (that is, the prototype ends with
    `,...)'), the compiler has no knowledge about the parameters
    that correspond to the `...' piece. (It does, of course,
    know about the parameters that precede it.)

    In these cases, you must either write the conversions explicitly or
    accept the "default argument promotions." Since `NULL' can be
    either `(void*)0' or plain `0' (or other equivalent forms), you
    don't really know exactly what you've written when you write an
    unadorned `NULL', so the conversion must be made explicitly.

    Recommended practices to ease the pain:

    - Always declare functions before using them. (In fact, this
    is mandatory under the latest "C99" Standard, and the compiler
    is required to complain if you fail to do this.)

    - Use argument prototypes in function declarations, so the
    compiler knows as much as possible about the function. This
    lets it make the proper conversions automatically, and lets
    it catch some kinds of mistakes.

    - The best way to declare a library function -- from the Standard
    library or from any other -- is to #include the appropriate
    header.

    If you always declare functions and always use prototypes, the
    only remaining situation you need to worry about is the arguments
    that match the `...' parameters of variadic functions.

    --
    Eric.Sosman@sun .com

    Comment

    • Arthur J. O'Dwyer

      #3
      Re: implicit type conversions


      On Wed, 2 Jun 2004, buda wrote:[color=blue]
      >
      > Let me see if I got this :)
      > 1. I know the rules for type conversions in arithmetic expressions[/color]

      No, probably not. But they're quite simple as long as you stay
      away from corner cases. Here's the rule of thumb: Unsigned trumps
      signed. Long trumps int. Short and char are automatically promoted
      to int (signed or unsigned, depending on the implementation limits).
      Void pointers can be converted to and from any other data pointer
      type silently and automatically. You can assign between floating-point
      and integer types silently (though it's not a good idea IMHO because
      it will usually cause lots of spurious compiler warnings). Everything
      else probably requires a cast.
      For the real rules, read the Standard.
      [color=blue]
      > 2. I know that an implicit type conversion is done at assignment, so
      > float x = 1.23;
      > int t = (int) x;
      > is equivalent to
      > int t = x;
      > (could the latter produce a warning on some complier?)[/color]

      Sure. On the DS9000, it produces "Warning: This program may or
      may not be standard C." More helpfully, most compilers will warn
      you about a possible "loss of precision" during the conversion.
      Neither warning is required by the Standard.
      [color=blue]
      > 3. I know that implicit conversions take place with function arguments, but
      > am a bit shaky here. I suppose that passing a char to a function accepting
      > int or long will always work, and those sort of conversions seem to make
      > sense. But what sort of things won't work here?[/color]

      Passing negative numbers to functions expecting 'unsigned' types
      is often dangerous, though well-defined by the Standard. Passing
      anything to a variadic function like 'printf' requires careful thought.
      [color=blue]
      > For example, the FAQ says
      > that the NULL pointer *must* be cast to the appropriate type when sent to a
      > function as an argument (so, for example, time(NULL) is incorrect, and
      > time( (time_t *) NULL) is correct?),[/color]

      Wrong. NULL must be cast *only* when passing it to a variadic function
      expecting a particular type of pointer. For example,

      printf("%p\n", NULL); is obviously wrong if #define NULL 0
      printf("%p\n", (void*)NULL); is correct in all cases
      [color=blue]
      > which seems to indicate that
      > conversions from (void *) to (some_type *) in function argument lists need
      > not be (isn't) implicit. If someone would clarify this, I'd be most grateful
      > (like which sort of things cause warnings, which need be cast and the like).[/color]

      (void*) and (some_type*) are mutually convertible whenever 'some_type'
      is a data type. (That is, a conversion between (void*) and (int(*)())
      requires a cast, and isn't even guaranteed to work at all. This is
      because (int(*)()) is a function pointer type, not a data pointer type.)

      Read the FAQ again, and then check the standard (Google "N869" for
      the last public draft thereof).

      HTH,
      -Arthur

      Comment

      • buda

        #4
        Re: implicit type conversions

        Thank you, all clear now :)


        Comment

        • CBFalconer

          #5
          Re: implicit type conversions

          Eric Sosman wrote:[color=blue]
          >[/color]
          .... snip ...[color=blue]
          >
          > - The best way to declare a library function -- from the
          > Standard library or from any other -- is to #include the
          > appropriate header.
          >
          > If you always declare functions and always use prototypes,
          > the only remaining situation you need to worry about is the
          > arguments that match the `...' parameters of variadic functions.[/color]

          So it appears to me that if the system declares NULL as (void *)0
          then the code:

          printf("%p\n", NULL);

          is well defined, but if the system simply declares NULL as 0 there
          could be a problem. This is fairly obvious in this case, but may
          not be if the pointer variable is passed in. The problem will
          _probably_ not arise if the sizes of int and void* are the same.
          This could be a sneaky bug, and should encourage always declaring
          NULL as (void*)0.

          --
          fix (vb.): 1. to paper over, obscure, hide from public view; 2.
          to work around, in a way that produces unintended consequences
          that are worse than the original problem. Usage: "Windows ME
          fixes many of the shortcomings of Windows 98 SE". - Hutchison


          Comment

          • Arthur J. O'Dwyer

            #6
            Re: implicit type conversions


            On Wed, 2 Jun 2004, CBFalconer wrote:
            [...][color=blue]
            > So it appears to me that if the system declares NULL as (void *)0
            > then the code:
            >
            > printf("%p\n", NULL);
            >
            > is well defined, but if the system simply declares NULL as 0 there
            > could be a problem. This is fairly obvious in this case, but may
            > not be if the pointer variable is passed in. The problem will
            > _probably_ not arise if the sizes of int and void* are the same.
            > This could be a sneaky bug, and should encourage always declaring
            > NULL as (void*)0.[/color]

            s/declaring/defining/, I would think is the correct terminology.
            Anyway...

            This is a sneaky bug that *only* arises if the programmer passes
            an unadorned 'NULL' to a variadic function expecting a pointer.
            What's more, the bug is only *fixable* if that variadic function
            expects a pointer to void (not any other kind of pointer). In
            practice, I bet this boils down to "This sneaky bug appears only
            when the programmer calls 'printf("%p", NULL)'", which obviously
            never, ever happens except in toy pedagogical programs. Which
            aren't really the focus of compiler implementors, I would think.

            So, while IMHO it does make more sense to define NULL using the
            "more strict" definition of (void*)0 rather than an unadorned 0,
            I don't think the otherwise-undefined behavior of a pathological
            and non-conforming program is a compelling argument for it. :)

            -Arthur

            Comment

            • Peter Slootweg

              #7
              Re: implicit type conversions


              "Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> wrote in message
              news:Pine.LNX.4 .58-035.04060217340 60.13503@unix47 .andrew.cmu.edu ...[color=blue]
              >
              > On Wed, 2 Jun 2004, CBFalconer wrote:
              > [...][color=green]
              > > So it appears to me that if the system declares NULL as (void *)0
              > > then the code:
              > >
              > > printf("%p\n", NULL);
              > >
              > > is well defined, but if the system simply declares NULL as 0 there
              > > could be a problem. This is fairly obvious in this case, but may
              > > not be if the pointer variable is passed in. The problem will
              > > _probably_ not arise if the sizes of int and void* are the same.
              > > This could be a sneaky bug, and should encourage always declaring
              > > NULL as (void*)0.[/color]
              >
              > s/declaring/defining/, I would think is the correct terminology.
              > Anyway...
              >
              > This is a sneaky bug that *only* arises if the programmer passes
              > an unadorned 'NULL' to a variadic function expecting a pointer.
              > What's more, the bug is only *fixable* if that variadic function
              > expects a pointer to void (not any other kind of pointer). In
              > practice, I bet this boils down to "This sneaky bug appears only
              > when the programmer calls 'printf("%p", NULL)'", which obviously
              > never, ever happens except in toy pedagogical programs. Which
              > aren't really the focus of compiler implementors, I would think.
              >
              > So, while IMHO it does make more sense to define NULL using the
              > "more strict" definition of (void*)0 rather than an unadorned 0,
              > I don't think the otherwise-undefined behavior of a pathological
              > and non-conforming program is a compelling argument for it. :)
              >
              > -Arthur[/color]

              what about the case where your variadic function expects NULL to terminate a
              list of pointers to void

              e.g. (not compiled)

              size_t myfunc(void *p1,...)
              {
              size_t c;
              va_list list;
              va_start(list,p 1);
              c = 0;
              while (p1 != NULL)
              {
              /* do something uninteresting with p1 - actually just count */
              c++;
              p1 = va_arg(list,voi d *);
              }
              return c;
              }



              Comment

              • Dan Pop

                #8
                Re: implicit type conversions

                In <Pine.LNX.4.5 8-035.04060217340 60.13503@unix47 .andrew.cmu.edu > "Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> writes:

                [color=blue]
                >On Wed, 2 Jun 2004, CBFalconer wrote:
                >[...][color=green]
                >> So it appears to me that if the system declares NULL as (void *)0
                >> then the code:
                >>
                >> printf("%p\n", NULL);
                >>
                >> is well defined, but if the system simply declares NULL as 0 there
                >> could be a problem. This is fairly obvious in this case, but may
                >> not be if the pointer variable is passed in. The problem will
                >> _probably_ not arise if the sizes of int and void* are the same.
                >> This could be a sneaky bug, and should encourage always declaring
                >> NULL as (void*)0.[/color]
                >
                > s/declaring/defining/, I would think is the correct terminology.
                >Anyway...
                >
                > This is a sneaky bug that *only* arises if the programmer passes
                >an unadorned 'NULL' to a variadic function expecting a pointer.
                >What's more, the bug is only *fixable* if that variadic function
                >expects a pointer to void (not any other kind of pointer). In
                >practice, I bet this boils down to "This sneaky bug appears only
                >when the programmer calls 'printf("%p", NULL)'", which obviously
                >never, ever happens except in toy pedagogical programs. Which
                >aren't really the focus of compiler implementors, I would think.
                >
                > So, while IMHO it does make more sense to define NULL using the
                >"more strict" definition of (void*)0 rather than an unadorned 0,
                >I don't think the otherwise-undefined behavior of a pathological
                >and non-conforming program is a compelling argument for it. :)[/color]

                A much more compelling argument for NULL as (void*)0 is the frequently
                seen assumption that NULL can be used anywhere a plain 0 does the job,
                e.g. the null character terminating a string (the NULL name is probably
                at the root of this confusion).

                Dan
                --
                Dan Pop
                DESY Zeuthen, RZ group
                Email: Dan.Pop@ifh.de

                Comment

                • Dan Pop

                  #9
                  Re: implicit type conversions

                  In <pOxvc.6044$OI5 .3532@edtnps84> "Peter Slootweg" <peter.slootweg @xtxexlxuxs.xnx ext> writes:

                  [color=blue]
                  >"Arthur J. O'Dwyer" <ajo@nospam.and rew.cmu.edu> wrote in message
                  >news:Pine.LNX. 4.58-035.04060217340 60.13503@unix47 .andrew.cmu.edu ...[color=green]
                  >>
                  >> On Wed, 2 Jun 2004, CBFalconer wrote:
                  >> [...][color=darkred]
                  >> > So it appears to me that if the system declares NULL as (void *)0
                  >> > then the code:
                  >> >
                  >> > printf("%p\n", NULL);
                  >> >
                  >> > is well defined, but if the system simply declares NULL as 0 there
                  >> > could be a problem. This is fairly obvious in this case, but may
                  >> > not be if the pointer variable is passed in. The problem will
                  >> > _probably_ not arise if the sizes of int and void* are the same.
                  >> > This could be a sneaky bug, and should encourage always declaring
                  >> > NULL as (void*)0.[/color]
                  >>
                  >> s/declaring/defining/, I would think is the correct terminology.
                  >> Anyway...
                  >>
                  >> This is a sneaky bug that *only* arises if the programmer passes
                  >> an unadorned 'NULL' to a variadic function expecting a pointer.
                  >> What's more, the bug is only *fixable* if that variadic function
                  >> expects a pointer to void (not any other kind of pointer). In
                  >> practice, I bet this boils down to "This sneaky bug appears only
                  >> when the programmer calls 'printf("%p", NULL)'", which obviously
                  >> never, ever happens except in toy pedagogical programs. Which
                  >> aren't really the focus of compiler implementors, I would think.
                  >>
                  >> So, while IMHO it does make more sense to define NULL using the
                  >> "more strict" definition of (void*)0 rather than an unadorned 0,
                  >> I don't think the otherwise-undefined behavior of a pathological
                  >> and non-conforming program is a compelling argument for it. :)
                  >>[/color]
                  >what about the case where your variadic function expects NULL to terminate a
                  >list of pointers to void[/color]

                  Use the obvious: (void *)NULL or (void *)0. Anything not equivalent to
                  one of these forms (or a null void pointer) is a bug.

                  Dan
                  --
                  Dan Pop
                  DESY Zeuthen, RZ group
                  Email: Dan.Pop@ifh.de

                  Comment

                  • Old Wolf

                    #10
                    Re: implicit type conversions

                    CBFalconer <cbfalconer@yah oo.com> wrote:[color=blue]
                    > So it appears to me that if the system declares NULL as (void *)0
                    > then the code:
                    >
                    > printf("%p\n", NULL);
                    >
                    > is well defined, but if the system simply declares NULL as 0 there
                    > could be a problem. This is fairly obvious in this case, but may
                    > not be if the pointer variable is passed in. The problem will
                    > _probably_ not arise if the sizes of int and void* are the same.[/color]

                    It would arise if 0 and (void *)0 have different representations
                    (which is not that uncommon)
                    [color=blue]
                    > This could be a sneaky bug, and should encourage always declaring
                    > NULL as (void*)0.[/color]

                    There are still problem situations, because (void *) could be a different
                    size to other pointer types, eg:

                    void put_strings(cha r *f1, ...)
                    {
                    va_list ap;
                    va_start(ap, f1);
                    while (f1 != NULL)
                    {
                    puts(f1);
                    f1 = va_arg(ap, char *);
                    }
                    va_end(ap);
                    }

                    If called with: put_strings("fo o", NULL); would cause UB even if
                    NULL is (void *)0.

                    Comment

                    • Sam Dennis

                      #11
                      Re: implicit type conversions

                      Old Wolf wrote:[color=blue]
                      > void put_strings(cha r *f1, ...)
                      >
                      > If called with: put_strings("fo o", NULL); would cause UB even if
                      > NULL is (void *)0.[/color]

                      Not in this case (pointers to void and `a character type' (normally
                      read as `all the character types') have identical representations ),
                      but it's certainly a concern for pointers to other types, functions
                      in particular.

                      --
                      ++acr@,ka"

                      Comment

                      • Dan Pop

                        #12
                        Re: implicit type conversions

                        In <slrncbvjua.50b .sam@ID-227112.user.uni-berlin.de> Sam Dennis <sam@malfunctio n.screaming.net > writes:
                        [color=blue]
                        >Old Wolf wrote:[color=green]
                        >> void put_strings(cha r *f1, ...)
                        >>
                        >> If called with: put_strings("fo o", NULL); would cause UB even if
                        >> NULL is (void *)0.[/color]
                        >
                        >Not in this case (pointers to void and `a character type' (normally
                        >read as `all the character types') have identical representations ),[/color]

                        Identical representation means exactly zilch in context. What you
                        need is identical argument passing mechanisms and the standard provides
                        no normative guarantees about that.

                        Dan
                        --
                        Dan Pop
                        DESY Zeuthen, RZ group
                        Email: Dan.Pop@ifh.de

                        Comment

                        • Sam Dennis

                          #13
                          Re: implicit type conversions

                          Dan Pop wrote:[color=blue]
                          > In <slrncbvjua.50b .sam@ID-227112.user.uni-berlin.de> Sam Dennis <sam@malfunctio n.screaming.net > writes:[color=green]
                          >>Old Wolf wrote:[color=darkred]
                          >>> void put_strings(cha r *f1, ...)
                          >>>
                          >>> If called with: put_strings("fo o", NULL); would cause UB even if
                          >>> NULL is (void *)0.[/color]
                          >>
                          >>Not in this case (pointers to void and `a character type' (normally
                          >>read as `all the character types') have identical representations ),[/color]
                          >
                          > What you need is identical argument passing mechanisms and the
                          > standard provides no normative guarantees about that.[/color]

                          That's probably true, but I doubt that there's any conforming
                          implementation in existence that does not follow the footnote
                          strongly suggesting this reading.

                          --
                          ++acr@,ka"

                          Comment

                          • Dan Pop

                            #14
                            Re: implicit type conversions

                            In <slrncc2561.50b .sam@ID-227112.user.uni-berlin.de> Sam Dennis <sam@malfunctio n.screaming.net > writes:
                            [color=blue]
                            >Dan Pop wrote:[color=green]
                            >> In <slrncbvjua.50b .sam@ID-227112.user.uni-berlin.de> Sam Dennis <sam@malfunctio n.screaming.net > writes:[color=darkred]
                            >>>Old Wolf wrote:
                            >>>> void put_strings(cha r *f1, ...)
                            >>>>
                            >>>> If called with: put_strings("fo o", NULL); would cause UB even if
                            >>>> NULL is (void *)0.
                            >>>
                            >>>Not in this case (pointers to void and `a character type' (normally
                            >>>read as `all the character types') have identical representations ),[/color]
                            >>
                            >> What you need is identical argument passing mechanisms and the
                            >> standard provides no normative guarantees about that.[/color]
                            >
                            >That's probably true, but I doubt that there's any conforming
                            >implementati on in existence that does not follow the footnote
                            >strongly suggesting this reading.[/color]

                            Are they still maintaining the DS9k?

                            Dan
                            --
                            Dan Pop
                            DESY Zeuthen, RZ group
                            Email: Dan.Pop@ifh.de

                            Comment

                            • Dave Thompson

                              #15
                              Re: implicit type conversions

                              On 4 Jun 2004 10:37:28 GMT, Dan.Pop@cern.ch (Dan Pop) wrote:
                              [color=blue]
                              > In <slrncbvjua.50b .sam@ID-227112.user.uni-berlin.de> Sam Dennis <sam@malfunctio n.screaming.net > writes:
                              >[color=green]
                              > >Old Wolf wrote:[color=darkred]
                              > >> void put_strings(cha r *f1, ...)
                              > >> [ and using va_arg to get as char* ]
                              > >> If called with: put_strings("fo o", NULL); would cause UB even if
                              > >> NULL is (void *)0.[/color]
                              > >
                              > >Not in this case (pointers to void and `a character type' (normally
                              > >read as `all the character types') have identical representations ),[/color]
                              >
                              > Identical representation means exactly zilch in context. What you
                              > need is identical argument passing mechanisms and the standard provides
                              > no normative guarantees about that.
                              >[/color]
                              It does in C99: 7.5.1.1p2 for va_arg, and 6.5.2.2p6 for (wholly)
                              unprototyped/K&R1 definitions. Also for (the shared range of)
                              corresponding signed and unsigned integers. Presumably if any
                              implementor wasn't already doing these and wasn't willing to change
                              they would have objected.

                              - David.Thompson1 at worldnet.att.ne t

                              Comment

                              Working...