-1

https://linux.die.net/man/3/stdarg

man stdarg(3) shows an example of how to program a variadic function. But the functions called by the outmost variadic function are not variadic.

Is there a way to call a variadic in a variadic function like this with all the arguments passed as is? If so, could anybody show me the details on how to do it?

void foo(char *fmt, ...) {
printf(fmt, ...) // not sure how to call a variadic function here ... is just ... from foo
}

EDIT: None of the answers in call printf using va_list clearly answers my question.

If the answer is "not possible", please clearly answer it as "not possible". Instead of providing anything irrelevant. I don't need any alternative solutions.

Also, if it is "not possible", could anybody prove why it is not possible. None of the answers in that link answers this. Therefore, this post should remain open to answer my questions specifically.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
user1424739
  • 11,937
  • 17
  • 63
  • 152
  • In general, you must call a function version that accepts a `va_list` argument. – Devolus May 11 '21 at 16:24
  • There's no general way to do this. When you write the variadic function, you must also provide a version that accepts a `va_list` argument if you want someone to be able to call it from their variadic function. – Barmar May 11 '21 at 16:25
  • Is the answer "not possible"? There is no way to call a variadic function from a variadic function with all the arguments passed as is? – user1424739 May 11 '21 at 16:29
  • Please reopen the post. None of the previous answers specifically address my questions. – user1424739 May 11 '21 at 16:40
  • There's no standard way to do this. It may be possible for a specific compiler and target using inline asm code and knowledge of how it packs a va_list. – Chris Dodd May 11 '21 at 16:52
  • The question of why remain unanswered. – user1424739 May 11 '21 at 16:56
  • 1
    Why? Because noone ever wanted or implemented such a feature, and they never bothered to standardize it. – Chris Dodd May 11 '21 at 16:57
  • No. You don't get my question. This is not a prove. How can you prove something nonexistent? Since you can not examine everything, this is not the way to prove it. To prove something is impossible, you will need to start with something that is known (for example how valist is implemented underlying C. Then, show that it is not possible to do what my question asked using this implementation of valist. – user1424739 May 11 '21 at 17:06
  • 1
    The point is that using a `va_list` is the standardized, accepted way of handling variable arguments. If your design depends on one variadic function calling another, you need to change your design. – dbush May 11 '21 at 17:29
  • @dbush Your reply still doesn't answer why it is not possible. You merely reiterate that it is not possible. – user1424739 May 11 '21 at 17:35
  • @user1424739: That's because noone is saying it is not possible, just that noone has bothered to do it (or standardize it) as it is not worth doing -- it would be much too expensive given that there are simpler ways of doing the same thing. – Chris Dodd May 11 '21 at 19:44
  • `None of the answers in that link answers this` what about the last answer? [this one](https://stackoverflow.com/a/23789807/9072753) – KamilCuk May 12 '21 at 22:08

1 Answers1

4

Actually it is possible in gcc, with a little known built-in feature that allows you to "construct" function calls. Reference here

See for example this question, which received the answer you're looking for, it just wasn't the most popular. Here's a repost of that example code to save you the click:

int my_printf(const char *fmt, ...) {
    void *args = __builtin_apply_args();
    printf("Hello there! Format string is %s\n", fmt);
    void *ret = __builtin_apply((void (*)())printf, args, 1000);
    __builtin_return(ret);
}

int main(void) {
    my_printf("%d %f %s\n", -37, 3.1415, "spam");
    return 0;
}

This feature hasn't (yet) been reimplemented in clang, though there is an interesting discussion about it you can read in the archives.

So to come back to your original question of possibility, I guess we would have to clarify what passes for "possible" in this case. The C standard has no way to reference a list of variadic arguments apart from a va_list. Compilers like gcc can put in their own extension to deal with this (like __builtin_apply), but they will always be non-portable and non-standard.

The next question you might be tempted to ask is "why", and I can really only speculate on the answer, but I believe it's probably because doing so would require putting additional constraints and requirements on the ABI and calling convention, something that the C and C++ specifications try to avoid wherever possible.

In general, a called function has no idea how much stuff has been pushed on the stack before its entry, and I don't know of any ABIs that require this information to be present in all cases. If foo() is going to "forward" its arguments to another variadic function, it will need to know how many things have been passed to it, and this information simply isn't available at compile time (where the call to a "next level" function will be constructed).

Only the person writing the function actually knows how to iterate over its call stack, and the chosen syntax for this is using va_list objects.

Of course it's not hard to see how you could create an ABI that allows passing argument counts and lengths, but it's an academic exercise if all of the world's libraries that you're actually going to call into don't conform to your ABI.

Jon Reeves
  • 2,426
  • 3
  • 14
  • 2
    Indeed, it's worth noting that `__builtin_apply` requires you to give it an upper bound on the number of bytes of stack to be copied, and so it cannot succeed in full generality. Also, it copies that number of bytes unconditionally, making it very inefficient when the number of arguments is usually small but could potentially be huge. – Nate Eldredge May 13 '21 at 01:51