va_copy

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

    #1

    va_copy

    Is the following code valid:

    void func(int va_flag, ...)
    {
    va_list va;
    va_start(va, va_flag);

    if (va_flag) { // indirect va_list
    va_copy(va, va_arg(va, va_list));
    }

    // [...] code using va

    va_end(va);
    }

    or it should absolutely be written as:

    void func(int va_flag, ...)
    {
    va_list va;
    va_start(va, va_flag);

    if (va_flag) { // indirect va_list
    va_list va0;
    va_copy(va0, va_arg(va, va_list));
    va_end(va);
    va_copy(va, va0);
    va_end(va0);
    }

    // [...] code using va

    va_end(va);
    }

    According to the norm, only the second case is correct, otherwise va_end
    would never be applied to the direct va if flag == 0. But the second
    case is also more complex, even if in principle it should generate the
    same code for a reasonable smart compiler (assuming va_end is a NOP).

    a+, ld.
  • Dave Thompson

    #2
    Re: va_copy

    On Fri, 20 Oct 2006 14:27:52 +0200, Laurent Deniau
    <laurent.deniau @cern.chwrote:
    Is the following code valid:
    >
    void func(int va_flag, ...)
    {
    va_list va;
    va_start(va, va_flag);
    >
    if (va_flag) { // indirect va_list
    va_copy(va, va_arg(va, va_list));
    }
    >
    // [...] code using va
    >
    va_end(va);
    }
    >
    or it should absolutely be written as:
    >
    void func(int va_flag, ...)
    <snip: use a temporary so it can va_end the one used to get the
    caller-provided va_list before (copying and) using that>
    According to the norm, only the second case is correct, otherwise va_end
    would never be applied to the direct va if flag == 0. But the second
    case is also more complex, even if in principle it should generate the
    same code for a reasonable smart compiler (assuming va_end is a NOP).
    >
    Actually I don't think even the second is completely guaranteed, since
    va_list can be any object type, even one which is modified by the
    default argument promotions and so cannot be safely fetched by va_arg.
    This isn't likely since it seems improbable that the information
    needed for a va_list can be smaller than a data pointer which in turn
    is rarely smaller than 'int', but I think it is permitted.

    If va_flag is used only for this I would probably instead make it a
    pointer to va_list which is either the address of the caller's va_list
    = use (a copy of?) that or null = use my own variable arg list.
    I think that's a clearer 'in-band' way of signalling the choice,
    probably at least as efficient, and totally Standard.

    Or just use the more common and arguably cleaner approach of having
    e.g. a separate func (?,...) which forwards to vfunc (va_list).

    - David.Thompson1 at worldnet.att.ne t

    Comment

    • Laurent Deniau

      #3
      Re: va_copy

      Dave Thompson wrote:
      On Fri, 20 Oct 2006 14:27:52 +0200, Laurent Deniau
      <laurent.deniau @cern.chwrote:
      >
      >
      >>Is the following code valid:
      >>
      >>void func(int va_flag, ...)
      >>{
      > va_list va;
      > va_start(va, va_flag);
      >>
      > if (va_flag) { // indirect va_list
      > va_copy(va, va_arg(va, va_list));
      > }
      >>
      > // [...] code using va
      >>
      > va_end(va);
      >>}
      >>
      >>or it should absolutely be written as:
      >>
      >>void func(int va_flag, ...)
      >
      >
      <snip: use a temporary so it can va_end the one used to get the
      caller-provided va_list before (copying and) using that>
      >
      >>According to the norm, only the second case is correct, otherwise va_end
      >>would never be applied to the direct va if flag == 0. But the second
      >>case is also more complex, even if in principle it should generate the
      >>same code for a reasonable smart compiler (assuming va_end is a NOP).
      >>
      >
      Actually I don't think even the second is completely guaranteed, since
      va_list can be any object type, even one which is modified by the
      default argument promotions and so cannot be safely fetched by va_arg.
      This isn't likely since it seems improbable that the information
      needed for a va_list can be smaller than a data pointer which in turn
      is rarely smaller than 'int', but I think it is permitted.
      >
      If va_flag is used only for this I would probably instead make it a
      Well, va_flag is not really there. I use a bit inside a required
      argument. But the goal is the same, that is to apply the reverse pattern
      of variadic function calling the va_list version. Instead, all such
      functions are variadic and if the va_list version is required, then the
      indirection bit must be set. I found this pattern more efficient than
      the classic one.
      pointer to va_list which is either the address of the caller's va_list
      = use (a copy of?) that or null = use my own variable arg list.
      I think that's a clearer 'in-band' way of signalling the choice,
      probably at least as efficient, and totally Standard.
      This is an option already studied, but I found some performance loss due
      to the use of this indirection. And it does not solve the problem (if any).
      Or just use the more common and arguably cleaner approach of having
      e.g. a separate func (?,...) which forwards to vfunc (va_list).
      This is an option that I cannot achieve for few reasons, one being
      efficiency.

      Thanks for your reply.

      Comment

      Working...