printf length modifier

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

    printf length modifier

    Hello,

    Does the following code invoke undefined behavior?

    #include <stdio.h>
    int main(void)
    {
    unsigned short int u = 42;
    printf("%u\n", u);
    return 0;
    }

    gcc doesn't seem to mind.
    $ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
    $ ./a.out
    42

    Is it mandatory to add the 'h' length modifier in the format string?

    unsigned short int u = 42;
    printf("%hu\n", u);

    Regards.
  • CBFalconer

    #2
    Re: printf length modifier

    Spoon wrote:
    >
    Does the following code invoke undefined behavior?
    >
    #include <stdio.h>
    int main(void)
    {
    unsigned short int u = 42;
    printf("%u\n", u);
    return 0;
    }
    Yes.
    >
    gcc doesn't seem to mind.
    $ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
    $ ./a.out
    42
    >
    Is it mandatory to add the 'h' length modifier in the format string?
    Yes. Add the -O (capital letter) option to the gcc run.

    --
    <http://www.cs.auckland .ac.nz/~pgut001/pubs/vista_cost.txt>
    <http://www.securityfoc us.com/columnists/423>
    <http://www.aaxnet.com/editor/edit043.html>
    cbfalconer at maineline.net


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

    Comment

    • Spoon

      #3
      Re: printf length modifier

      CBFalconer wrote:
      Spoon wrote:
      >Does the following code invoke undefined behavior?
      >>
      >#include <stdio.h>
      >int main(void)
      >{
      > unsigned short int u = 42;
      > printf("%u\n", u);
      > return 0;
      >}
      >
      Yes.
      >
      >gcc doesn't seem to mind.
      >$ gcc -Wall -Wextra -std=c89 -pedantic zzz.c
      >$ ./a.out
      >42
      >>
      >Is it mandatory to add the 'h' length modifier in the format string?
      >
      Yes. Add the -O (capital letter) option to the gcc run.
      $ gcc -O -Wall -Wextra -std=c89 -pedantic zzz.c
      $ ./a.out
      42

      $ gcc -O3 -Wall -Wextra -std=c89 -pedantic zzz.c
      $ ./a.out
      42

      :-)

      Aren't short int parameters "widened" to int in variadic function calls?

      Regards.

      Comment

      • Flash Gordon

        #4
        Re: printf length modifier

        Spoon wrote, On 26/04/07 10:33:
        Hello,
        >
        Does the following code invoke undefined behavior?
        >
        #include <stdio.h>
        int main(void)
        {
        unsigned short int u = 42;
        printf("%u\n", u);
        return 0;
        }
        <snip>
        Is it mandatory to add the 'h' length modifier in the format string?
        >
        unsigned short int u = 42;
        printf("%hu\n", u);
        unsigned short is likely to be promoted to int rather than signed int,
        so using %u is lying. Anyway, why would you want to use a possibly
        incorrect format specifier when you know the definitely correct one?
        --
        Flash Gordon

        Comment

        • Flash Gordon

          #5
          Re: printf length modifier

          Spoon wrote, On 26/04/07 12:20:
          CBFalconer wrote:
          >Spoon wrote:
          >>Does the following code invoke undefined behavior?
          >>>
          >>#include <stdio.h>
          >>int main(void)
          >>{
          >> unsigned short int u = 42;
          >> printf("%u\n", u);
          >> return 0;
          >>}
          >>
          >Yes.
          <snip>
          >>Is it mandatory to add the 'h' length modifier in the format string?
          >>
          >Yes. Add the -O (capital letter) option to the gcc run.
          <snip>
          Aren't short int parameters "widened" to int in variadic function calls?
          You are using unsigned short, which could be widened to int (most
          probable) or unsigned int, and using the format specifier for an
          unsigned int. int and unsigned int are NOT the same thing.

          There is also the big question of why you do not want to use what you
          know is definitely the correct format specifier.
          --
          Flash Gordon

          Comment

          • Spoon

            #6
            Re: printf length modifier

            Flash Gordon wrote:
            Spoon wrote, On 26/04/07 12:20:
            >CBFalconer wrote:
            >>Spoon wrote:
            >>>Does the following code invoke undefined behavior?
            >>>>
            >>>#include <stdio.h>
            >>>int main(void)
            >>>{
            >>> unsigned short int u = 42;
            >>> printf("%u\n", u);
            >>> return 0;
            >>>}
            >>>
            >>Yes.
            >
            <snip>
            >
            >>>Is it mandatory to add the 'h' length modifier in the format string?
            >>>
            >>Yes. Add the -O (capital letter) option to the gcc run.
            >
            <snip>
            >
            >Aren't short int parameters "widened" to int in variadic function calls?
            >
            You are using unsigned short, which could be widened to int (most
            probable) or unsigned int, and using the format specifier for an
            unsigned int. int and unsigned int are NOT the same thing.
            (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
            equivalent because both conversions are well-defined.
            There is also the big question of why you do not want to use what you
            know is definitely the correct format specifier.
            u is, in fact, an uint16_t and I don't know for sure that u is an
            unsigned short int. It might be an unsigned int.

            Regards.

            Comment

            • Flash Gordon

              #7
              Re: printf length modifier

              Spoon wrote, On 26/04/07 14:31:
              Flash Gordon wrote:
              >Spoon wrote, On 26/04/07 12:20:
              >>CBFalconer wrote:
              >>>Spoon wrote:
              >>>>Does the following code invoke undefined behavior?
              >>>>>
              >>>>#include <stdio.h>
              >>>>int main(void)
              >>>>{
              >>>> unsigned short int u = 42;
              >>>> printf("%u\n", u);
              >>>> return 0;
              >>>>}
              >>>>
              >>>Yes.
              >>
              ><snip>
              >>
              >>>>Is it mandatory to add the 'h' length modifier in the format string?
              >>>>
              >>>Yes. Add the -O (capital letter) option to the gcc run.
              >>
              ><snip>
              >>
              >>Aren't short int parameters "widened" to int in variadic function calls?
              >>
              >You are using unsigned short, which could be widened to int (most
              >probable) or unsigned int, and using the format specifier for an
              >unsigned int. int and unsigned int are NOT the same thing.
              >
              (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
              equivalent because both conversions are well-defined.
              True, but it is reasonable to assume that in the real code other values
              will be used. It is not unreasonable to expect that some of those values
              will be too large to fit in a signed short, or why bother with the extra
              typing?
              >There is also the big question of why you do not want to use what you
              >know is definitely the correct format specifier.
              >
              u is, in fact, an uint16_t and I don't know for sure that u is an
              unsigned short int. It might be an unsigned int.
              If this is C99 code then I believe there is a macro provided in C99 to
              solve this problem. Otherwise, cast the value to a known type for printing.
              printf("%u\n", (unsigned int)u);
              Or, alternatively, as you know that any value that will fit in an
              unsigned 16 bit integer will fit in an unsigned short (which may be more
              than 16 bits, but not less), cast to unsigned short and use the h modifier.
              --
              Flash Gordon

              Comment

              • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

                #8
                Re: printf length modifier

                Spoon wrote:
                Flash Gordon wrote:
                Spoon wrote, On 26/04/07 12:20:
                CBFalconer wrote:
                >Spoon wrote:
                >>Does the following code invoke undefined behavior?
                >>>
                >>#include <stdio.h>
                >>int main(void)
                >>{
                >> unsigned short int u = 42;
                >> printf("%u\n", u);
                >> return 0;
                >>}
                >>
                >Yes.
                <snip>
                >>Is it mandatory to add the 'h' length modifier in the format string?
                >>
                >Yes. Add the -O (capital letter) option to the gcc run.
                <snip>
                Aren't short int parameters "widened" to int in variadic function calls?
                You are using unsigned short, which could be widened to int (most
                probable) or unsigned int, and using the format specifier for an
                unsigned int. int and unsigned int are NOT the same thing.
                >
                (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
                equivalent because both conversions are well-defined.
                Huh? I really don't understand what you're trying to say here. Could
                you please explain?
                There is also the big question of why you do not want to use what you
                know is definitely the correct format specifier.
                >
                u is, in fact, an uint16_t and I don't know for sure that u is an
                unsigned short int. It might be an unsigned int.
                The format specifier for uint16_t is PRIu16.

                #include <stdio.h>
                #include <inttypes.h>

                #ifndef UINT16_MAX
                #error uint16_t not supported
                #endif

                int main(void)
                {
                uint16_t u = 42;
                printf("%" PRIu16 "\n", u);
                return 0;
                }

                Comment

                • Flash Gordon

                  #9
                  Re: printf length modifier

                  Harald van Dijk wrote, On 26/04/07 18:51:
                  Spoon wrote:
                  <snip>
                  >(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
                  >equivalent because both conversions are well-defined.
                  >
                  Huh? I really don't understand what you're trying to say here. Could
                  you please explain?
                  The standard guarantees that the representation of all positive values
                  of int is the same as the representation of those values in an unsigned
                  int. At least, I assume that is what Spoon meant, although if so it
                  could be phrased better.
                  --
                  Flash Gordon

                  Comment

                  • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

                    #10
                    Re: printf length modifier

                    Flash Gordon wrote:
                    Harald van Dijk wrote, On 26/04/07 18:51:
                    Spoon wrote:
                    >
                    <snip>
                    >
                    (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
                    equivalent because both conversions are well-defined.
                    Huh? I really don't understand what you're trying to say here. Could
                    you please explain?
                    >
                    The standard guarantees that the representation of all positive values
                    of int is the same as the representation of those values in an unsigned
                    int. At least, I assume that is what Spoon meant, although if so it
                    could be phrased better.
                    Thanks for the explanation. I don't think there's any prohibition
                    against an implementation passing the object type along with the
                    value, and bombing out if the passed type does not exactly match the
                    expected type for printf(), but only bombing out if the passed type
                    does not loosely match the expected type for va_arg(). Aside from an
                    extremely strict debugging implementation though, I can't imagine why
                    anyone would want to do that.

                    Comment

                    • Keith Thompson

                      #11
                      Re: printf length modifier

                      Spoon <devnull@localh ost.comwrites:
                      Flash Gordon wrote:
                      >Spoon wrote, On 26/04/07 12:20:
                      >>CBFalconer wrote:
                      >>>Spoon wrote:
                      >>>>Does the following code invoke undefined behavior?
                      >>>>>
                      >>>>#include <stdio.h>
                      >>>>int main(void)
                      >>>>{
                      >>>> unsigned short int u = 42;
                      >>>> printf("%u\n", u);
                      >>>> return 0;
                      >>>>}
                      >>>>
                      >>>Yes.
                      ><snip>
                      >>
                      >>>>Is it mandatory to add the 'h' length modifier in the format string?
                      >>>>
                      >>>Yes. Add the -O (capital letter) option to the gcc run.
                      ><snip>
                      >>
                      >>Aren't short int parameters "widened" to int in variadic function calls?
                      >You are using unsigned short, which could be widened to int (most
                      >probable) or unsigned int, and using the format specifier for an
                      >unsigned int. int and unsigned int are NOT the same thing.
                      >
                      (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int
                      are equivalent because both conversions are well-defined.
                      Conversion has nothing to do with it. Conversion between int and
                      double is well-defined, but passing a double argument for a "%d"
                      format invokes undefined behavior. No conversion, other than argument
                      promotions, occurs for variadic arguments.

                      It's true that the value 42 is guaranteed to have the same
                      *representation * in types int and unsigned int. Specifically, C99
                      6.2.5p9 says:

                      The range of nonnegative values of a signed integer type is a
                      subrange of the corresponding unsigned integer type, and the
                      representation of the same value in each type is the same.

                      with a footnote:

                      The same representation and alignment requirements are meant to
                      imply interchangeabil ity as arguments to functions, return values
                      from functions, and members of unions.

                      So you can look carefully through the standard for proof that the code
                      will work properly whether the argument is promoted to int or to
                      unsigned int (note that this depends on a footnote, which is
                      nonnormative). Note that you'll also need to depend on the
                      implementer getting this right. It's also likely that the argument
                      will be promoted to int on all the platforms you use, so you'll never
                      have a chance to test the case where it's promoted to unsigned int,
                      just in case you missed something.

                      Or you can write simpler code that doesn't depend on a potentially
                      shaky line of reasoning.
                      >There is also the big question of why you do not want to use what
                      >you know is definitely the correct format specifier.
                      >
                      u is, in fact, an uint16_t and I don't know for sure that u is an
                      unsigned short int. It might be an unsigned int.
                      So convert it to unsigned int and use "%u".

                      Incidentally, there's another subtle issue here. The standard's
                      description of printf() describes the required formats for various
                      types. It's almost certainly safe to assume that printf() uses the
                      same mechanisms as a user-written variadic function, so you can safely
                      assume that argument promotion occurs as you would expect. But the
                      standard doesn't *quite* come out and say so. (There was a lengthy
                      discussion of this in comp.std.c a while ago.) I don't think it's
                      anything to worry about, but it's enough to make me more cautious with
                      format strings than I absolutely need to be.

                      --
                      Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                      San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
                      "We must do something. This is something. Therefore, we must do this."
                      -- Antony Jay and Jonathan Lynn, "Yes Minister"

                      Comment

                      • Jack Klein

                        #12
                        Re: printf length modifier

                        On 26 Apr 2007 13:29:45 -0700, Harald van D?k <truedfx@gmail. com>
                        wrote in comp.lang.c:
                        Flash Gordon wrote:
                        Harald van D?k wrote, On 26/04/07 18:51:
                        Spoon wrote:
                        <snip>
                        >(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
                        >equivalent because both conversions are well-defined.
                        >
                        Huh? I really don't understand what you're trying to say here. Could
                        you please explain?
                        The standard guarantees that the representation of all positive values
                        of int is the same as the representation of those values in an unsigned
                        int. At least, I assume that is what Spoon meant, although if so it
                        could be phrased better.
                        >
                        Thanks for the explanation. I don't think there's any prohibition
                        against an implementation passing the object type along with the
                        value, and bombing out if the passed type does not exactly match the
                        expected type for printf(), but only bombing out if the passed type
                        does not loosely match the expected type for va_arg(). Aside from an
                        extremely strict debugging implementation though, I can't imagine why
                        anyone would want to do that.
                        Actually there is such a prohibition, 6.5.2.2 p6. It applies to both
                        functions without prototypes and to the variable arguments of variadic
                        functions:

                        <begin>
                        If the expression that denotes the called function has a type that
                        does not include a prototype, the integer promotions are performed on
                        each argument, and arguments that have type float are promoted to
                        double. These are called the default argument promotions. If the
                        number of arguments does not equal the number of parameters, the
                        behavior is undefined. If the function is defined with a type that
                        includes a prototype, and either the prototype ends with an ellipsis
                        (, ...) or the types of the arguments after promotion are not
                        compatible with the types of the parameters, the behavior is
                        undefined. If the function is defined with a type that does not
                        include a prototype, and the types of the arguments after promotion
                        are not compatible with those of the parameters after promotion, the
                        behavior is undefined, except for the following cases:

                        — one promoted type is a signed integer type, the other promoted type
                        is the corresponding unsigned integer type, and the value is
                        representable in both types;

                        — both types are pointers to qualified or unqualified versions of a
                        character type or void.
                        <end>

                        So it makes no difference if the unsigned short is promoted to signed
                        or unsigned int, the actual int object has exactly the same bit
                        representation and is passed the same way.

                        --
                        Jack Klein
                        Home: http://JK-Technology.Com
                        FAQs for
                        comp.lang.c http://c-faq.com/
                        comp.lang.c++ http://www.parashift.com/c++-faq-lite/
                        alt.comp.lang.l earn.c-c++

                        Comment

                        • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

                          #13
                          Re: printf length modifier

                          Jack Klein wrote:
                          On 26 Apr 2007 13:29:45 -0700, Harald van D?k <truedfx@gmail. com>
                          wrote in comp.lang.c:
                          >
                          Flash Gordon wrote:
                          Harald van D?k wrote, On 26/04/07 18:51:
                          Spoon wrote:
                          >
                          <snip>
                          >
                          (Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int are
                          equivalent because both conversions are well-defined.

                          Huh? I really don't understand what you're trying to say here. Could
                          you please explain?
                          >
                          The standard guarantees that the representation of all positive values
                          of int is the same as the representation of those values in an unsigned
                          int. At least, I assume that is what Spoon meant, although if so it
                          could be phrased better.
                          Thanks for the explanation. I don't think there's any prohibition
                          against an implementation passing the object type along with the
                          value, and bombing out if the passed type does not exactly match the
                          expected type for printf(), but only bombing out if the passed type
                          does not loosely match the expected type for va_arg(). Aside from an
                          extremely strict debugging implementation though, I can't imagine why
                          anyone would want to do that.
                          >
                          Actually there is such a prohibition, 6.5.2.2 p6.
                          6.5.2.2p6 describes function calls where the function declaration
                          lacks a prototype. Any definition of printf must include a prototype.
                          6.5.2.2p7 describes function calls where the function declaration
                          includes a prototype, and contains no exception similar to what you
                          quoted.

                          Comment

                          Working...