# Julia equivalent to C's vsnprintf

**URL:** <https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467>\
**Category:** General Usage\
**Created:** [December 11, 2023, 9:37pm UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467 "2023-12-11T21:37:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mpeters2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mpeters2/32/202247_2.png) [@mpeters2](https://discourse.julialang.org/u/mpeters2)\
**Post date:** [December 11, 2023, 9:37pm UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/1 "2023-12-11T21:37:42Z")

</div>

I’m try to translate some C code to Julia, but I’m a little stumped with how to tackle this. First, there is this macro as well as two global variables:

```julia
// Shared buffer for variadic text
static char* fc_buffer = NULL;
static unsigned int fc_buffer_size = 1024;

#define FC_EXTRACT_VARARGS(buffer, start_args) \
{ \
    va_list lst; \
    va_start(lst, start_args); \
    vsnprintf(buffer, fc_buffer_size, start_args, lst); \
    va_end(lst); \
}

```

and here is an example of it being used:

```julia
FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...)
{
    if(formatted_text == NULL || font == NULL)
        return FC_MakeRect(x, y, 0, 0);

    FC_EXTRACT_VARARGS(fc_buffer, formatted_text);

    set_color_for_all_caches(font, font->default_color);

    return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
}

```

It’s from a C file called “SDL\_FontCache.c”, and the function is supposed to allow you to draw formated text on the screen (a graphical printf). For example:

```julia
FC_Draw(font, renderer, 0, 0, "This is %s.\n It works.", "example text"); 

```

I think what is throwing me is (1) I’m unfamiliar with vsnprintf(), (2) I’m unfamiliar with the whole va\_list macro stuff. I’m sure there is a simple answer using a varargs function and the @sprintf macro, but I’m stumped.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 11, 2023, 9:48pm UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/2 "2023-12-11T21:48:25Z")

</div>

Yeah, the macro `@sprintf` doesn’t work for dynamic things like this. With Julia v1.6 or later, you can use the `Printf.format` function:

```julia
julia> using Printf

julia> f(str, args...) = Printf.format(Printf.Format(str), args...)
FC_Draw (generic function with 1 method)

julia> f("%s: %f", "hello", 1.234)
"hello: 1.234000"

```

---

<div class="post-metadata">

**Author:** ![mpeters2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mpeters2/32/202247_2.png) [@mpeters2](https://discourse.julialang.org/u/mpeters2)\
**Post date:** [December 12, 2023, 12:12am UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/3 "2023-12-12T00:12:13Z")

</div>

That get’s half-way there, but I still need to be able to send the args as a lists to Printf.format

I can do this:

```julia
julia> f(str, args...) = Printf.format(Printf.Format(str), args...)
f (generic function with 1 method)

julia> f("%s, %s", "cat", "dog")
"cat, dog"

julia> f("%s, %s %d", "cat", "dog", 2)
"cat, dog 2"

```

But I need it to do something like this:

```julia
zyz = f("%s, %s %d", ["cat", "dog", 2] )
ERROR: ArgumentError: Number of format specifiers and number of provided args differ: 3 != 1

```

I guess I could just build a new string by iterating through the format string until I hit a “%” (followed by a char or two and a space), grab the next item off the argument list and sprintf()-it onto the string I’m building, but I was hoping there might be a less brute-force way,

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [December 12, 2023, 12:17am UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/4 "2023-12-12T00:17:13Z")

</div>

> [@mpeters2](#):
>
> `f(str, args...) = Printf.format(Printf.Format(str), args...)`

If you want to accept lists instead of individual arguments in `f`, you can just omit the `...` on the left-hand side:

```julia
julia> g(str, args) = Printf.format(Printf.Format(str), args...)
g (generic function with 1 method)

julia> g("%s, %s %d", ["cat", "dog", 2])
"cat, dog 2"

```

---

<div class="post-metadata">

**Author:** ![mpeters2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mpeters2/32/202247_2.png) [@mpeters2](https://discourse.julialang.org/u/mpeters2)\
**Post date:** [December 12, 2023, 3:38am UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/5 "2023-12-12T03:38:52Z")

</div>

I ended up doing this:

```julia
using Printf

function stringParser(formatString::String, arguments::Array)
	formatters = ['s', 'd', 'f']
	done = false
	myString = ""

	sprintf(str, args...) = Printf.format(Printf.Format(str), args...)

	stringLength = length(formatString)
	i = 1
	argIndex = 1

	while !done
		c = formatString[i]
		if c != '%'
			myString = myString * c
		else
			j = 0
			subString = ""
			done2 = false
			while !done2
				c2 = formatString[i+j]
				if c2 in formatters
					done2 = true
				end
				subString = subString * c2
				j += 1
			end
			println("subString = ", subString,"\n")
			formattedString = sprintf(subString, arguments[argIndex])
			myString = myString * formattedString
			argIndex += 1
			i = i + j - 1
		end
		i += 1
		if i > stringLength
			done = true
		end
	end
	return myString
end
#-------------------------------------------------------------------
output = stringParser("My name is %s. I am %2.1f years old", ["Steve", 99.92])
println(output)

```

…Which gives me this for an answer:

```julia
subString = %s

subString = %2.1f

My name is Steve. I am 99.9 years old

```

Thanks for the Printf.format(). That knowledge is priceless.

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [December 12, 2023, 8:28am UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/6 "2023-12-12T08:28:38Z")

</div>

As far as I can tell @ericphanson 's one liner does the same and without bugs. why not use that?

---

<div class="post-metadata">

**Author:** ![mpeters2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mpeters2/32/202247_2.png) [@mpeters2](https://discourse.julialang.org/u/mpeters2)\
**Post date:** [December 12, 2023, 12:29pm UTC](https://discourse.julialang.org/t/julia-equivalent-to-cs-vsnprintf/107467/7 "2023-12-12T12:29:11Z")

</div>

Doh! I didn’t see @ericphanson’s one liner. Indeed, that is much more elegant!
