4

Using the <stdarg.h> header, one can make a function that has a variable number of arguments, but:

  1. To start using a va_list, you need to use a va_start macro that needs to know how many arguments there, but the printf & ... that are using va_list don't need the argument count. How can I create a function that doesn't need the argument count like printf?

  2. Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list? (so in pseudocode, it would be like void printfRipOff(const char* format, ...) {printf(format, ...);})

14
  • 2
    va_start macro that needs to know how many arguments there va_start macro does not need to know how many arguments there are. How can I create a function that doesn't need the argument count like printf? printf "knows" the argument count - it counts the number of % in the format string not followed by another %. say I want to create a function that takes a va_list & instead of using it, passes it to another function that requires a va_list? Let's say that, and? So write that function. Commented Oct 6, 2022 at 18:09
  • 2
    sprintf and printf are identical except that printf prints to stdout and sprintf prints to the char* passed as the first argument Commented Oct 6, 2022 at 18:17
  • 2
    See also question 15.4 in the C FAQ list. Question 15.5 and the rest of section 15 may be of interest to you, also. Commented Oct 6, 2022 at 18:27
  • 2
    If what you wanted was provided by a person who also offered an answer, you should consider clicking the hollow check-mark to indicate that you have accepted the answer. I would also suggest up-clicking any other answers that you found helpful. Commented Oct 6, 2022 at 18:38
  • 2
    Rather than putting "thanks" in the question, you should accept an answer. Commented Oct 6, 2022 at 18:39

3 Answers 3

3

Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list?

Look at function vprintf( const char * format, va_list arg ); for one example of a function that takes a va_list as an input parameter.

It is basically used this way:

#include <stdio.h>
#include <stdarg.h>

void CountingPrintf(const char* format, ...)
{
   static int counter = 1;
   printf("Line # %d: ", counter++); // Print a Counter up front

   va_list args;
   va_start(args, format); // Get the args
   vprintf(format, args);  // Pass the "args" through to another printf function.

   va_end(args);
}

int main(void) {
    CountingPrintf("%s %s\n", "Hello", "World");
    CountingPrintf("%d + %d == %d\n", 2, 3, 2+3);
    
    return 0;
}

Output:

Line # 1: Hello World
Line # 2: 2 + 3 == 5
Sign up to request clarification or add additional context in comments.

Comments

2
  1. Functions like printf() and scanf() have the format string argument that tells them the number and types of the arguments that must have been provided by the function call.

    If you're writing your own function, you must have some way of knowing how many arguments were provided and their types. It may be that they are all the same type. It may be that they're all pointers and you can use a null pointer to indicate the end of the arguments. Otherwise, you probably have to include a count.

  2. You can do that as long as provided the called function expects a va_list. There are caveats (see C11 §7.16 Variable arguments) but they're manageable with a little effort.

A very common idiom is that you have a function int sometask(const char *fmt, ...) and a second function int vsometask(const char *fmt, va_list args), and you implement the first as a simple call to the second:

int sometask(const char *fmt, ...)
{
    va_list args;
    va_start(fmt, args);
    int rc = vsometask(fmt, args);
    va_end(args);
    return rc;
}

The second function does the real work, of course, or calls on other functions to do the real work.


In the question, you say:

va_start macro that needs to know how many arguments …

No; the va_start macro only needs to know which argument is the one before the ellipsis — the argument name before the , ... in the function definition.


In a comment, you say:

This is what I'm trying to write, but it didn't work.

string format(const char* text, ...)
{
    // temporary string used for formatting
    string formattedString;
    initializeString(&formattedString, text);
    // start the va_list
    va_list args;
    va_start(text, args);
    // format
    sprintf(formattedString.array, text, args);
    // end the va_list
    va_end(args);
    return formattedString;
}

As noted by abelenky in a comment, you need to use vsprintf():

string format(const char* text, ...)
{
    string formattedString;
    initializeString(&formattedString, text);
    va_list args;
    va_start(text, args);
    vsprintf(formattedString.array, text, args);
    va_end(args);
    return formattedString;
}

That assumes that the formattedString has enough space in the array for the formatted result. It isn't immediately obvious how that's organized, but presumably you know how it works and it works safely. Consider using vsnprintf() if you can determine the space available in the formattedString.

4 Comments

this is what I'm trying to write, didn't work. string format(const char* text, ...) { // temporary string used for formatting string formattedString; initializeString(&formattedString, text); // start the va_list va_list args; va_start(text, args); // format sprintf(formattedString.array, text, args); // end the va_list va_end(args); return formattedString; }
You need to be calling vsprintf instead of sprintf. The v prefix means "Takes a Variable number of arguments."
@KianFakheriAghdam - That comment would be a great addition to your post, thus explaining what you tried, and ask for pointers on why it did not work. Please consider editing your post to add that content. Be sure to include what precisely you are using for a compiler and what libraries. It looks like you may be studying cs50 as string is not a native type in C. C would of course use char * in place of string.
I will upvote y'all answers. I am new here & don't really know how things work. also the string is actually a struct made by myself, I'm creating a C library that has a ton of nice features & that string is a run-time malloc string.
2

The printf and scanf family of functions don't need to be explicitly passed the length of the va_list because they are able to infer the number of arguments by the format string.

For instance, in a call like:

printf("%d %c %s\n", num, c, "Hello");

printf is able to examine the first parameter, the format string, and see that it contains a %d, a %c, and a %s in that order, so it can assume that there are three additional arguments, the first of which is a signed int, the second is a char and the third is a char* that it may assume is a pointer to a null-terminated string.

To write a similar function that does not need to be explicitly told how many arguments are being passed, you must find a way to subtly give it some information allowing it to infer the number and types of the arguments in va_list.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.