Help with Variable-Length Argument Lists

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

    #1

    Help with Variable-Length Argument Lists

    Greetings everyone,

    I wrote a function to learn about variable-length argument lists. I
    wonder if there is a better way to detect the end of the argument list
    than using a sentinel value like the one I am using (NULL in this
    example) or an argument count parameter (ugh).

    The following function concatenates a series of C-style strings. I am
    aware of the fact that not allocating enough memory for `dst` results
    in UB (gave me a segmentation fault).

    #include <stdarg.h>

    char *
    append (
    char * dst, // destination string buffer
    const char * base, // first string
    const char * append, // second string
    /* const char * appN */ ... // n strings
    /* , NULL */ // sentinel null indicating list end
    )
    {
    va_list ap;
    char * eosdst = dst;
    const char * cp = NULL;

    /* copy base to dst */
    while ((*eosdst = *base))
    ++eosdst, ++base;

    /* copy append to dst */
    while ((*eosdst = *append))
    ++eosdst, ++append;

    /* copy remaining strings if they exist. NULL -- terminate */
    va_start (ap, append);
    while (NULL != (cp = va_arg (ap, const char*)))
    while ((*eosdst = *cp))
    ++eosdst, ++cp;
    va_end (ap);

    return (dst);
    }

    Sample Usage:
    #include <stdio.h>

    /* ... */

    int
    main (int argc, char ** pp_argv)
    {
    char buf[200];
    char * tst = "test";
    char * teststring2 = "This is some more text.\nSee if this works
    well.";

    append (buf, "--d--", teststring2, teststring2, tst, "\n", NULL);
    printf (buf);

    return (0);
    }

    Any help will be appreciated. If you have suggestions, please feel free
    to comment so I can improve. Thank you.

    Regards,
    JB

  • Eric Sosman

    #2
    Re: Help with Variable-Length Argument Lists

    Jonathan Burd wrote:[color=blue]
    > Greetings everyone,
    >
    > I wrote a function to learn about variable-length argument lists. I
    > wonder if there is a better way to detect the end of the argument list
    > than using a sentinel value like the one I am using (NULL in this
    > example) or an argument count parameter (ugh).[/color]

    The fundamental requirement is that you need to know
    whether a "next argument" exists (and what type it is)
    before attempting to retrieve it with va_arg(). You can
    use any imaginable computation to come up with this yes/no
    result. However, the <stdarg.h> mechanism itself doesn't
    provide any information you can use as an input for the
    computation; you must compute yes/no from other sources.

    Two popular mechanisms are to use a sentinel value or
    to use an argument count (which could, of course, actually
    count pairs of arguments, or triples, or some other grouping).
    A less popular mechanism is to imitate the printf() family,
    where one of the "fixed" arguments provides information
    about the number and types of the variable arguments. But
    these three are by no means an exhaustive catalog; anything
    at all will work if it can produce the answer you need. The
    trade-offs are usually the mechanism's complexity (simpler
    is better, other things being equal) and its vulnerability
    to misuse (the compiler can't do a lot of checking on the
    "..." arguments).
    [color=blue]
    > The following function concatenates a series of C-style strings. I am
    > aware of the fact that not allocating enough memory for `dst` results
    > in UB (gave me a segmentation fault).
    >
    > char *
    > append (
    > char * dst, // destination string buffer
    > const char * base, // first string
    > const char * append, // second string
    > /* const char * appN */ ... // n strings
    > /* , NULL */ // sentinel null indicating list end
    > )
    > [...]
    >
    > Sample Usage:
    > #include <stdio.h>
    >
    > /* ... */
    >
    > append (buf, "--d--", teststring2, teststring2, tst, "\n", NULL);[/color]

    Here's an example of the "vulnerabil ity to misuse" mentioned
    above: write `(char*)NULL' instead of just `NULL'. Question 5.2
    in the comp.lang.c Frequently Asked Questions (FAQ) list



    explains why.

    --
    Eric.Sosman@sun .com

    Comment

    • CBFalconer

      #3
      Re: Help with Variable-Length Argument Lists

      Jonathan Burd wrote:[color=blue]
      >
      > I wrote a function to learn about variable-length argument lists.
      > I wonder if there is a better way to detect the end of the argument
      > list than using a sentinel value like the one I am using (NULL in
      > this example) or an argument count parameter (ugh).
      >
      > The following function concatenates a series of C-style strings. I
      > am aware of the fact that not allocating enough memory for `dst`
      > results in UB (gave me a segmentation fault).
      >
      > #include <stdarg.h>
      >
      > char *
      > append (
      > char * dst, // destination string buffer
      > const char * base, // first string
      > const char * append, // second string
      > /* const char * appN */ ... // n strings
      > /* , NULL */ // sentinel null indicating list end
      > )
      > {
      > va_list ap;
      > char * eosdst = dst;
      > const char * cp = NULL;
      >
      > /* copy base to dst */
      > while ((*eosdst = *base))
      > ++eosdst, ++base;
      >
      > /* copy append to dst */
      > while ((*eosdst = *append))
      > ++eosdst, ++append;
      >
      > /* copy remaining strings if they exist. NULL -- terminate */
      > va_start (ap, append);
      > while (NULL != (cp = va_arg (ap, const char*)))
      > while ((*eosdst = *cp))
      > ++eosdst, ++cp;
      > va_end (ap);
      >
      > return (dst);
      > }
      >
      > Sample Usage:
      > #include <stdio.h>
      >
      > /* ... */
      >
      > int
      > main (int argc, char ** pp_argv)
      > {
      > char buf[200];
      > char * tst = "test";
      > char * teststring2 = "This is some more text.\nSee if this works
      > well.";
      >
      > append (buf, "--d--", teststring2, teststring2, tst, "\n", NULL);
      > printf (buf);
      >
      > return (0);
      > }
      >
      > Any help will be appreciated. If you have suggestions, please feel free
      > to comment so I can improve. Thank you.[/color]

      You should properly indent your code, using spaces, not tabs. At
      any rate variadic functions are invitations to misuse and are error
      prone. You should avoid them. Especially in this case, since the
      standard sprintf() routine is already available to perform the same
      job, is more flexible, uses familiar parameters, and is already
      available. With C99 I believe snprintf() is much safer.

      --
      Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
      Available for consulting/temporary embedded and systems.
      <http://cbfalconer.home .att.net> USE worldnet address!


      Comment

      • Jonathan Burd

        #4
        Re: Help with Variable-Length Argument Lists

        Actually, it's Google's posting mechanism. It formatted the code
        automatically. I use the 2-space indentation style.

        Regards,
        JB

        Comment

        • Kenny McCormack

          #5
          Re: Help with Variable-Length Argument Lists

          In article <41BF1B2B.413D2 9EF@yahoo.com>,
          CBFalconer <cbfalconer@wor ldnet.att.net> wrote:[color=blue]
          >Especially in this case, since the
          >standard sprintf() routine is already available to perform the same
          >job, is more flexible, uses familiar parameters, and is already
          >available. With C99 I believe snprintf() is much safer.[/color]

          I wonder. Is it ever possible in this NG to post something like "I am
          trying to solve <newProblemThat HasNeverBeenSol vedBefore>, using technique
          <A>, but since newProblemThatH asNeverBeenSolv edBefore is complicated and
          possibly proprietary, I'd prefer not to explain
          newProblemThatH asNeverBeenSolv edBefore. So, I'm going to discuss the
          problems I am having with technique <A>, but I'm going to use this made up
          example", and not get a response that says "'made-up-example' has already
          been solved; why are you trying to reinvent the wheel?" ?

          Comment

          • Keith Thompson

            #6
            Re: Help with Variable-Length Argument Lists

            gazelle@yin.int eraccess.com (Kenny McCormack) writes:[color=blue]
            > In article <41BF1B2B.413D2 9EF@yahoo.com>,
            > CBFalconer <cbfalconer@wor ldnet.att.net> wrote:[color=green]
            >>Especially in this case, since the
            >>standard sprintf() routine is already available to perform the same
            >>job, is more flexible, uses familiar parameters, and is already
            >>available. With C99 I believe snprintf() is much safer.[/color]
            >
            > I wonder. Is it ever possible in this NG to post something like "I am
            > trying to solve <newProblemThat HasNeverBeenSol vedBefore>, using technique
            > <A>, but since newProblemThatH asNeverBeenSolv edBefore is complicated and
            > possibly proprietary, I'd prefer not to explain
            > newProblemThatH asNeverBeenSolv edBefore. So, I'm going to discuss the
            > problems I am having with technique <A>, but I'm going to use this made up
            > example", and not get a response that says "'made-up-example' has already
            > been solved; why are you trying to reinvent the wheel?" ?[/color]

            Probably, but I see no sign of any
            newProblemThatH asNeverBeenSolv edBefore in this thread.

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

            Working...