va_arg()

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

    va_arg()

    Hello,

    I have a question about va_arg() usage :
    Is there any way how I can check or ensure at compile time that
    va_arg() is not called when there are
    no next arguments anymore.
    I understood that calling va_arg() when there are no next arguments
    causes an undefined behaviour.

    Thanks

  • Richard Tobin

    #2
    Re: va_arg()

    In article <1161872784.766 186.213920@k70g 2000cwa.googleg roups.com>,
    LIT <tony.libbrecht @dana.comwrote:
    >Is there any way how I can check or ensure at compile time that
    >va_arg() is not called when there are
    >no next arguments anymore.
    No, your program has to work that out for itself. Typically one
    of the arguments indicates how many other arguments there are (as
    in printf()) or a special value (such as 0) is used as an extra
    terminating argument.

    -- Richard

    Comment

    • mark_bluemel@pobox.com

      #3
      Re: va_arg()


      LIT wrote:
      I have a question about va_arg() usage :
      Is there any way how I can check or ensure at compile time that
      va_arg() is not called when there are
      no next arguments anymore.
      No - it is essential that you have a means (usually based on your first
      argument) to determine how many times to invoke va_arg().

      See (for example)

      and

      I understood that calling va_arg() when there are no next arguments
      causes an undefined behaviour.
      Yep. (My manual page talks of "random errors" :-)

      Comment

      • LIT

        #4
        Re: va_arg()


        mark_bluemel@po box.com schreef:
        LIT wrote:
        >
        I have a question about va_arg() usage :
        Is there any way how I can check or ensure at compile time that
        va_arg() is not called when there are
        no next arguments anymore.
        >
        No - it is essential that you have a means (usually based on your first
        argument) to determine how many times to invoke va_arg().
        >
        See (for example)

        and

        >
        I understood that calling va_arg() when there are no next arguments
        causes an undefined behaviour.
        >
        Yep. (My manual page talks of "random errors" :-)
        I understand
        Nevertheless, if I have a function like this :

        foo(unsigned char Nvars, ...)
        {
        unsigned int i;
        unsigned int test[10];
        va_list tag ;
        va_start(tag,Nv ars);
        for (i=0 ; i<Nvars ; i++)
        {
        test[i] = va_arg(tag, unsigned int);
        }
        va_end(tag)
        }

        and I do this (eg. accidentally, during coding) :

        foo(4, x, y) ; (x and y are unsigned int params),

        then there is no clear means to detect this at compile time

        Comment

        • David Resnick

          #5
          Re: va_arg()


          LIT wrote:
          mark_bluemel@po box.com schreef:
          >
          LIT wrote:
          I have a question about va_arg() usage :
          Is there any way how I can check or ensure at compile time that
          va_arg() is not called when there are
          no next arguments anymore.
          No - it is essential that you have a means (usually based on your first
          argument) to determine how many times to invoke va_arg().

          See (for example)

          and

          I understood that calling va_arg() when there are no next arguments
          causes an undefined behaviour.
          Yep. (My manual page talks of "random errors" :-)
          >
          I understand
          Nevertheless, if I have a function like this :
          >
          foo(unsigned char Nvars, ...)
          {
          unsigned int i;
          unsigned int test[10];
          va_list tag ;
          va_start(tag,Nv ars);
          for (i=0 ; i<Nvars ; i++)
          {
          test[i] = va_arg(tag, unsigned int);
          }
          va_end(tag)
          }
          >
          and I do this (eg. accidentally, during coding) :
          >
          foo(4, x, y) ; (x and y are unsigned int params),
          >
          then there is no clear means to detect this at compile time
          When we had this issue, I wrote a perl script that scanned our source
          files to ensure that all calls to a predefined set of varargs functions
          had a NULL as the last argument, that being what we used as a sentinel.
          It wasn't perfect, but it was helpful. You might be able to come up
          with a similar tool that meets your needs.

          -David

          Comment

          • mark_bluemel@pobox.com

            #6
            Re: va_arg()


            LIT wrote:
            if I have a function like this :
            >
            foo(unsigned char Nvars, ...)
            and I do this (eg. accidentally, during coding) :
            >
            foo(4, x, y) ; (x and y are unsigned int params),
            >
            then there is no clear means to detect this at compile time
            That's true - because the compiler doesn't know (and the language
            provides no means of defining) that the first parameter to foo() has
            any specific meaning.

            The foo() implementation and the foo() invocation are independently
            parsed and compiled (they could be in separate source files, you just
            happened to combine declaring and defining foo() in your example).

            Comment

            • Laurent Deniau

              #7
              Re: va_arg()

              LIT wrote:
              mark_bluemel@po box.com schreef:
              >
              >
              >>LIT wrote:
              >>
              >>
              >>>I have a question about va_arg() usage :
              >>>Is there any way how I can check or ensure at compile time that
              >>>va_arg() is not called when there are
              >>>no next arguments anymore.
              >>
              >>No - it is essential that you have a means (usually based on your first
              >>argument) to determine how many times to invoke va_arg().
              >>
              >>See (for example)
              >>http://docs.mandragor.org/files/Prog...C-faq/s15.html
              >>and
              >>http://docs.mandragor.org/files/Prog...faq/q15.8.html
              >>
              >>
              >>>I understood that calling va_arg() when there are no next arguments
              >>>causes an undefined behaviour.
              >>
              >>Yep. (My manual page talks of "random errors" :-)
              >
              >
              I understand
              Nevertheless, if I have a function like this :
              >
              foo(unsigned char Nvars, ...)
              {
              unsigned int i;
              unsigned int test[10];
              va_list tag ;
              va_start(tag,Nv ars);
              for (i=0 ; i<Nvars ; i++)
              {
              test[i] = va_arg(tag, unsigned int);
              }
              va_end(tag)
              }
              >
              and I do this (eg. accidentally, during coding) :
              >
              foo(4, x, y) ; (x and y are unsigned int params),
              >
              then there is no clear means to detect this at compile time
              You can compute the number of arguments automatically by writing a macro
              with the same name and use the macro PP_NARG I posted on comp.std.c some
              time ago
              (http://groups.google.com.au/group/co...e4a3fb?hl=en):

              extern void foo(int n, ...);

              #define foo(...) foo(PP_NARG(__V A_ARGS__)-1, __VA_ARGS__)

              foo(x,y) -foo(2,x,y)

              The case:

              foo() -foo(0)

              is a bit more complex but possible.

              a+, ld.

              Comment

              • David Tiktin

                #8
                Re: va_arg()

                On 26 Oct 2006, "LIT" <tony.libbrecht @dana.comwrote:
                Nevertheless, if I have a function like this :
                >
                foo(unsigned char Nvars, ...)
                {
                unsigned int i;
                unsigned int test[10];
                va_list tag ;
                va_start(tag,Nv ars);
                for (i=0 ; i<Nvars ; i++)
                {
                test[i] = va_arg(tag, unsigned int);
                }
                va_end(tag)
                }
                >
                and I do this (eg. accidentally, during coding) :
                >
                foo(4, x, y) ; (x and y are unsigned int params),
                >
                then there is no clear means to detect this at compile time
                I'd love to hear about a clean, portable solution to this, but I don't
                know of one. In the case you give, where the first argument is the
                number of varargs, you could use a macro to help a little:

                #define FOO_ARGS_1(a) 1, (a)
                #define FOO_ARGS_2(a,b) 2, (a), (b)

                etc. I'm not claiming it's pretty, but you should at least get a
                compiler warning if you invoke one of the macros with the wrong number
                of arguments.

                Dave

                --
                D.a.v.i.d T.i.k.t.i.n
                t.i.k.t.i.n [at] a.d.v.a.n.c.e.d .r.e.l.a.y [dot] c.o.m

                Comment

                • Eric Sosman

                  #9
                  Re: va_arg()



                  LIT wrote On 10/26/06 11:23,:
                  [...]
                  Nevertheless, if I have a function like this :
                  >
                  foo(unsigned char Nvars, ...)
                  {
                  unsigned int i;
                  unsigned int test[10];
                  va_list tag ;
                  va_start(tag,Nv ars);
                  for (i=0 ; i<Nvars ; i++)
                  {
                  test[i] = va_arg(tag, unsigned int);
                  }
                  va_end(tag)
                  }
                  >
                  and I do this (eg. accidentally, during coding) :
                  >
                  foo(4, x, y) ; (x and y are unsigned int params),
                  >
                  then there is no clear means to detect this at compile time
                  Right, because the compiler doesn't know how you are going
                  to figure out the number and types of the optional arguments.
                  The scheme you use could be arbitrarily complicated: Maybe the
                  number of optional arguments is the square root of the first
                  argument, or maybe foo() stops looking for optional arguments
                  once their running sum exceeds the value of the first one, or
                  maybe the first argument is actually a bunch of bit-fields that
                  encode descriptions of the optional arguments, or ...

                  Some compilers have been "taught" the rules for variable-
                  argument library functions (Standard and otherwise), and can
                  do at least a partial validity check at compile time. At least
                  one compiler provides a way for you, the programmer, to state
                  that your print_in_colors () function is "printf-like" and can
                  be checked similarly. But I haven't heard of a compiler that
                  allows you to add new checking rules of your own.

                  By the way: Elsethread, someone mentioned using NULL as
                  a sentinel to mark the end of the list of optional arguments.
                  Thought question: Why is this a bad idea, and how could it
                  be made better? (Hint: What is the type of the expression
                  the NULL macro expands to?)

                  --
                  Eric.Sosman@sun .com

                  Comment

                  • Christopher Benson-Manica

                    #10
                    Re: va_arg()

                    Eric Sosman <Eric.Sosman@su n.comwrote:
                    By the way: Elsethread, someone mentioned using NULL as
                    a sentinel to mark the end of the list of optional arguments.
                    Thought question: Why is this a bad idea, and how could it
                    be made better? (Hint: What is the type of the expression
                    the NULL macro expands to?)
                    I assume you're talking about the general case - obviously NULL as a
                    sentinel could not work for a function such as printf() where the
                    type of each argument varies. I fail to see how using a sentinel
                    value to terminate a list of arguments *of the same type* is a bad
                    idea and I assume that's not what you were getting at.

                    --
                    C. Benson Manica | I *should* know what I'm talking about - if I
                    cbmanica(at)gma il.com | don't, I need to know. Flames welcome.

                    Comment

                    • David Resnick

                      #11
                      Re: va_arg()

                      Christopher Benson-Manica wrote:
                      Eric Sosman <Eric.Sosman@su n.comwrote:
                      >
                      By the way: Elsethread, someone mentioned using NULL as
                      a sentinel to mark the end of the list of optional arguments.
                      Thought question: Why is this a bad idea, and how could it
                      be made better? (Hint: What is the type of the expression
                      the NULL macro expands to?)
                      >
                      I assume you're talking about the general case - obviously NULL as a
                      sentinel could not work for a function such as printf() where the
                      type of each argument varies. I fail to see how using a sentinel
                      value to terminate a list of arguments *of the same type* is a bad
                      idea and I assume that's not what you were getting at.
                      >
                      I think his point is that you need to cast NULL to void* when passing
                      to a varargs function because it may be just a naked 0 and int may be
                      smaller than void*. I didn't make up the code in question, it
                      preceeded me. But fixing it (with a cast or some other approach)
                      doesn't seem worthwhile to me as it is unlikely to break any time soon.

                      -David

                      Comment

                      • Keith Thompson

                        #12
                        Re: va_arg()

                        Christopher Benson-Manica <ataru@norge.fr eeshell.orgwrit es:
                        Eric Sosman <Eric.Sosman@su n.comwrote:
                        > By the way: Elsethread, someone mentioned using NULL as
                        >a sentinel to mark the end of the list of optional arguments.
                        >Thought question: Why is this a bad idea, and how could it
                        >be made better? (Hint: What is the type of the expression
                        >the NULL macro expands to?)
                        >
                        I assume you're talking about the general case - obviously NULL as a
                        sentinel could not work for a function such as printf() where the
                        type of each argument varies. I fail to see how using a sentinel
                        value to terminate a list of arguments *of the same type* is a bad
                        idea and I assume that's not what you were getting at.
                        The point is that we don't *know* the type of the expression the NULL
                        macro expands to; it could be either int or void* (there are other
                        possibilities).

                        "(void*)NUL L" is a better sentinel value.

                        --
                        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.

                        Comment

                        • Keith Thompson

                          #13
                          Re: va_arg()

                          "David Resnick" <lndresnick@gma il.comwrites:
                          Christopher Benson-Manica wrote:
                          >Eric Sosman <Eric.Sosman@su n.comwrote:
                          >>
                          By the way: Elsethread, someone mentioned using NULL as
                          a sentinel to mark the end of the list of optional arguments.
                          Thought question: Why is this a bad idea, and how could it
                          be made better? (Hint: What is the type of the expression
                          the NULL macro expands to?)
                          >>
                          >I assume you're talking about the general case - obviously NULL as a
                          >sentinel could not work for a function such as printf() where the
                          >type of each argument varies. I fail to see how using a sentinel
                          >value to terminate a list of arguments *of the same type* is a bad
                          >idea and I assume that's not what you were getting at.
                          >
                          I think his point is that you need to cast NULL to void* when passing
                          to a varargs function because it may be just a naked 0 and int may be
                          smaller than void*. I didn't make up the code in question, it
                          preceeded me. But fixing it (with a cast or some other approach)
                          doesn't seem worthwhile to me as it is unlikely to break any time soon.
                          What do you mean by "any time soon"? It could break the moment you
                          recompile it on a 64-bit platform.

                          You don't actually have to wait for the code to fail before you fix
                          it.

                          --
                          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.

                          Comment

                          • Eric Sosman

                            #14
                            Re: va_arg()



                            Keith Thompson wrote On 10/26/06 14:55,:
                            Christopher Benson-Manica <ataru@norge.fr eeshell.orgwrit es:
                            >
                            >>Eric Sosman <Eric.Sosman@su n.comwrote:
                            >>
                            >> By the way: Elsethread, someone mentioned using NULL as
                            >>>a sentinel to mark the end of the list of optional arguments.
                            >>>Thought question: Why is this a bad idea, and how could it
                            >>>be made better? (Hint: What is the type of the expression
                            >>>the NULL macro expands to?)
                            >>
                            >>I assume you're talking about the general case - obviously NULL as a
                            >>sentinel could not work for a function such as printf() where the
                            >>type of each argument varies. I fail to see how using a sentinel
                            >>value to terminate a list of arguments *of the same type* is a bad
                            >>idea and I assume that's not what you were getting at.
                            >
                            >
                            The point is that we don't *know* the type of the expression the NULL
                            macro expands to; it could be either int or void* (there are other
                            possibilities).
                            >
                            "(void*)NUL L" is a better sentinel value.
                            Right. Or (char*)NULL, or (struct thing*)NULL, or
                            whatever pointer type the function expects to retrieve
                            with va_arg(). The point I wanted to make is that a
                            "bare" NULL makes an unreliable sentinel, because its
                            type is implementation-defined and quite likely wrong
                            for the purpose.

                            --
                            Eric.Sosman@sun .com

                            Comment

                            • David Resnick

                              #15
                              Re: va_arg()


                              Keith Thompson wrote:
                              "David Resnick" <lndresnick@gma il.comwrites:
                              Christopher Benson-Manica wrote:
                              Eric Sosman <Eric.Sosman@su n.comwrote:
                              >
                              By the way: Elsethread, someone mentioned using NULL as
                              a sentinel to mark the end of the list of optional arguments.
                              Thought question: Why is this a bad idea, and how could it
                              be made better? (Hint: What is the type of the expression
                              the NULL macro expands to?)
                              >
                              I assume you're talking about the general case - obviously NULL as a
                              sentinel could not work for a function such as printf() where the
                              type of each argument varies. I fail to see how using a sentinel
                              value to terminate a list of arguments *of the same type* is a bad
                              idea and I assume that's not what you were getting at.
                              I think his point is that you need to cast NULL to void* when passing
                              to a varargs function because it may be just a naked 0 and int may be
                              smaller than void*. I didn't make up the code in question, it
                              preceeded me. But fixing it (with a cast or some other approach)
                              doesn't seem worthwhile to me as it is unlikely to break any time soon.
                              >
                              What do you mean by "any time soon"? It could break the moment you
                              recompile it on a 64-bit platform.
                              >
                              The code in question is in a rather stable state (past QA/load
                              tested/released to customers). Changing a few hundred lines with no
                              actual functional defect would clearly not be approved -- and rightly
                              so I think. I don't consider fixing this critical, just something to
                              keep in mind, particularly for when we migrate to 64 bits, where no
                              doubt other code will be destabilized too. With our current headers,
                              wouldn't matter even then for our C files, as NULL is defined as
                              (void*) 0, but those system headers could change too, and as our
                              sources include both C and C++ it will break at least in the C++ files
                              as NULL there is 0...
                              You don't actually have to wait for the code to fail before you fix
                              it.
                              Depending on the state of a project and the perceived risk of the
                              failure, sometimes you do.

                              -David

                              Comment

                              Working...