Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 10:57:35 UTC, Luis wrote: Read https://dlang.org/spec/arrays.html#strings and try to use std.string.toStringz (http://dlang.org/phobos/std_string.html#.toStringz) Yes, but that's not what you use when you want to avoid allocation.
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 04:12:13 UTC, Mike Parker wrote: On Wednesday, 2 March 2016 at 01:39:13 UTC, David G. Maziero wrote: Consider the following function: void RenderText( FontBMP font, int x, int y, const char* text ) { for( int r=0; text[r]!='\0'; ++r ) { You're asking for trouble here. There's no guarantee that any D string is going to be null terminated. String literals are, but beyond that, all bets are off. char[256] text; sprintf( [0], "Player: pos:%.3f - speed:%.3f", player.position, player.speed ); Instead of sprintf, look into using std.format.sformat [1] (see below). It's equivalent to std.format.format, but allows you to provide a buffer. RenderText( font, 0, 0, cast(char*)text ); It's considered bad form to cast an array to a pointer like this. If you need a pointer to an array, just use the ptr property: text.ptr. Always be aware of the null terminator situation, though, when passing to C. I could simply do "RenderText(font,0,0,"FPS: "~to!string(fps));" Won't compile without using the .ptr property (or casting, which again, you shouldn't do). Moreover, you run into the null terminator problem. "FPS :" will be null terminated because it's a literal, but the string produced by concatentating it with the result of to!string would not be. Read https://dlang.org/spec/arrays.html#strings and try to use std.string.toStringz (http://dlang.org/phobos/std_string.html#.toStringz)
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 05:04:37 UTC, David G. Maziero wrote: I figured out what I wanted. Thanks for your answer Mike, sorry to bother you though. [...] Even null-terminated be sure to profile your loop, for isn't garanteed to be faster than foreach at all and foreach is definitely safer.
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 05:04:37 UTC, David G. Maziero wrote: void RenderText( FontBMP font, int x, int y, const char* text, Just one more correction for future reference, RenderText should be extern(C) void RenderText... in order for it to work correctly with va_start/etc.
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 05:04:37 UTC, David G. Maziero wrote: char[256] buff; va_list ap; va_start( ap, text ); sprintf( buff.ptr, text, ap ); va_end( ap ); Sorry again, where it reads "sprintf" should be "vsprintf".
Re: Formatting a string on a variadic parameter function without using GC
I figured out what I wanted. Thanks for your answer Mike, sorry to bother you though. Here's the result: void RenderText( FontBMP font, int x, int y, const char* text, ... ) { SDL_Rect rect1, rect2; rect2.x = x; rect2.y = y; rect2.w = font.width; rect2.h = font.height; rect1.w = font.width; rect1.h = font.height; char[256] buff; va_list ap; va_start( ap, text ); sprintf( buff.ptr, text, ap ); va_end( ap ); for( int r=0; buff[r]!='\0'; ++r ) { char letter = buff[r]; rect1.x = font.width*(letter%font.horizontal_count); rect1.y = font.height*(letter/font.horizontal_count); if( letter>=33 ) SDL_RenderCopy( g_renderer, font.texture, , ); rect2.x += font.spacing_x; if( letter==10 ) { rect2.x = x; rect2.y += font.spacing_y; } } } Since the "string" is built by sprintf, it'll be null-terminated. Sorry for posting without doing more research. I didn't realise I could use va_start/va_end just like in C.
Re: Formatting a string on a variadic parameter function without using GC
I forgot to add that the "RenderText(font,0,0,"FPS: "~to!string(fps));" was an older version where it wasn't const char *, but string. And I was using a foreach, so no null-termination. But that's beyond the point of not using GC.
Re: Formatting a string on a variadic parameter function without using GC
Yes, I'm aware of the null-termination thing. I might have pasted code that I already changed. But I already messed with sformat, and it seems that it does use the GC. I've put @nogc in RenderText, and the compiler says sformat uses GC, so I don't know. But the thing is, I don't want to build the string before calling RenderText, I want RenderText to do it.
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 04:12:13 UTC, Mike Parker wrote: char buf[1024]; Ugh. And the proper declaration in D: char[1024] buf;
Re: Formatting a string on a variadic parameter function without using GC
On Wednesday, 2 March 2016 at 01:39:13 UTC, David G. Maziero wrote: Consider the following function: void RenderText( FontBMP font, int x, int y, const char* text ) { for( int r=0; text[r]!='\0'; ++r ) { You're asking for trouble here. There's no guarantee that any D string is going to be null terminated. String literals are, but beyond that, all bets are off. char[256] text; sprintf( [0], "Player: pos:%.3f - speed:%.3f", player.position, player.speed ); Instead of sprintf, look into using std.format.sformat [1] (see below). It's equivalent to std.format.format, but allows you to provide a buffer. RenderText( font, 0, 0, cast(char*)text ); It's considered bad form to cast an array to a pointer like this. If you need a pointer to an array, just use the ptr property: text.ptr. Always be aware of the null terminator situation, though, when passing to C. I could simply do "RenderText(font,0,0,"FPS: "~to!string(fps));" Won't compile without using the .ptr property (or casting, which again, you shouldn't do). Moreover, you run into the null terminator problem. "FPS :" will be null terminated because it's a literal, but the string produced by concatentating it with the result of to!string would not be. but I want to avoid GC entirely. The ideal scenario is to have something like "void RenderText( /*etc*/, const char* fmt, ... )" but I can't seem to figure a way to pass the variadic parameters to sprintf. Any ideas? With sformat, something like this (not tested): import std.format; char buf[1024]; auto fmt = sformat(buf, "Foo: %s", 42); if(fmt.length < buf.length) buf[fmt.length] = 0; else buf[$-1] = 0; RenderText(blah, blah, buf.ptr); sformat returns a slice of the buffer containing the formatted string. You can use its length to guarantee the buffer is null terminated.