digitalmars.D.learn - Compile time format string check
- Ada (37/37) Mar 22 I have managed to write a function dprintf that will expand the
- Ada (2/4) Mar 22 also, the code is written with BetterC mode in mind.
- Richard (Rikki) Andrew Cattermole (5/5) Mar 22 If its a string literal it is already handled as part of bindings:
- Ada (8/14) Mar 22 I clearly said compile-time. maybe you misspoke.
- Richard (Rikki) Andrew Cattermole (5/17) Mar 22 The only way to do it at CT, is either with the pragma with a string
- Ada (4/16) Mar 22 In that case, how would you do it with the pragma or the template
- Richard (Rikki) Andrew Cattermole (3/22) Mar 22 Start with the pragma, I linked the docs for it.
- Ada (7/30) Mar 23 Hmm, just to be clear. The pragma just says that the function
- Richard (Rikki) Andrew Cattermole (59/92) Mar 23 Yeah you are a tad on your own on this one.
I have managed to write a function dprintf that will expand the
string argument to (length, pointer).
But now I wish there was a way to verify the format string if it
actually matches the rest of the parameters.
%.\*s should match with string
%s should match with char*
Is there a way to do it at compile time without using template
instantiation?
Here is the code for dprintf (any suggestions for nicer code are
welcome):
import core.stdc.stdio : printf, fgets, stdin;
import core.stdc.stdlib : malloc;
import core.stdc.string : memcpy;
import std.typecons : tuple;
auto expandArg(T)(T arg)
{
static if (is(T == string))
return tuple(cast(int)arg.length, arg.ptr);
else
return tuple(arg);
}
auto expandAll()
{
return tuple();
}
auto expandAll(T, Rest...)(T first, Rest rest)
{
return tuple(
expandArg(first).expand,
expandAll(rest).expand
);
}
void dprintf(Args...)(const char* fmt, Args args)
{
auto expanded = expandAll(args);
printf(fmt, expanded.expand);
}
Mar 22
On Sunday, 22 March 2026 at 21:57:19 UTC, Ada wrote:Is there a way to do it at compile time without using template instantiation?also, the code is written with BetterC mode in mind.
Mar 22
If its a string literal it is already handled as part of bindings: https://dlang.org/spec/pragma.html#printf I understand that you may be wanting a runtime error, but I'd suggest disallowing that entirely and go with a template parameter to provide your format to make sure its seeable to the compiler.
Mar 22
On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:If its a string literal it is already handled as part of bindings: https://dlang.org/spec/pragma.html#printf I understand that you may be wanting a runtime error, but I'd suggest disallowing that entirely and go with a template parameter to provide your format to make sure its seeable to the compiler.I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc) Can you help me rewrite my code to properly verify that the format specifiers match the arguments? If it's possible without templates, otherwise with templates.
Mar 22
On 23/03/2026 6:29 PM, Ada wrote:On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:The only way to do it at CT, is either with the pragma with a string literal for the format, or the format must be provided via a template parameter. You cannot do this, with a function parameter at CT.If its a string literal it is already handled as part of bindings: https://dlang.org/spec/pragma.html#printf I understand that you may be wanting a runtime error, but I'd suggest disallowing that entirely and go with a template parameter to provide your format to make sure its seeable to the compiler.I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc)
Mar 22
On Monday, 23 March 2026 at 05:33:05 UTC, Richard (Rikki) Andrew Cattermole wrote:On 23/03/2026 6:29 PM, Ada wrote:In that case, how would you do it with the pragma or the template parameter?On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:The only way to do it at CT, is either with the pragma with a string literal for the format, or the format must be provided via a template parameter. You cannot do this, with a function parameter at CT.[...]I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc)
Mar 22
On 23/03/2026 6:36 PM, Ada wrote:On Monday, 23 March 2026 at 05:33:05 UTC, Richard (Rikki) Andrew Cattermole wrote:Start with the pragma, I linked the docs for it. Parsing out the format spec by itself isn't a fun job and is libc dependent.On 23/03/2026 6:29 PM, Ada wrote:In that case, how would you do it with the pragma or the template parameter?On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:The only way to do it at CT, is either with the pragma with a string literal for the format, or the format must be provided via a template parameter. You cannot do this, with a function parameter at CT.[...]I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc)
Mar 22
On Monday, 23 March 2026 at 05:46:15 UTC, Richard (Rikki) Andrew Cattermole wrote:On 23/03/2026 6:36 PM, Ada wrote:Hmm, just to be clear. The pragma just says that the function marked with it will follow the C99 Standard 7.19.6.1. Does that standard specify that custom format specifiers can be defined by any chance? Because that's essentially what I am trying to achieve.On Monday, 23 March 2026 at 05:33:05 UTC, Richard (Rikki) Andrew Cattermole wrote:Start with the pragma, I linked the docs for it. Parsing out the format spec by itself isn't a fun job and is libc dependent.On 23/03/2026 6:29 PM, Ada wrote:In that case, how would you do it with the pragma or the template parameter?On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:The only way to do it at CT, is either with the pragma with a string literal for the format, or the format must be provided via a template parameter. You cannot do this, with a function parameter at CT.[...]I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc)
Mar 23
On 23/03/2026 8:13 PM, Ada wrote:On Monday, 23 March 2026 at 05:46:15 UTC, Richard (Rikki) Andrew Cattermole wrote:No.On 23/03/2026 6:36 PM, Ada wrote:Hmm, just to be clear. The pragma just says that the function marked with it will follow the C99 Standard 7.19.6.1. Does that standard specify that custom format specifiers can be defined by any chance?On Monday, 23 March 2026 at 05:33:05 UTC, Richard (Rikki) Andrew Cattermole wrote:Start with the pragma, I linked the docs for it. Parsing out the format spec by itself isn't a fun job and is libc dependent.On 23/03/2026 6:29 PM, Ada wrote:In that case, how would you do it with the pragma or the template parameter?On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew Cattermole wrote:The only way to do it at CT, is either with the pragma with a string literal for the format, or the format must be provided via a template parameter. You cannot do this, with a function parameter at CT.[...]I clearly said compile-time. maybe you misspoke. It's a bit of a nuisance because the function call then doesn't resemble C that much anymore. (it's called betterc)Because that's essentially what I am trying to achieve.Yeah you are a tad on your own on this one. Here is one way to do it with recursive functions. I had to create a indexOf util function as std.algorithm appears that it might've had a regression (WONTFIX) for betterC. ```d size_t indexOf(string haystack, char needle) { foreach(i, c; haystack) { if (c == needle) return i; } return haystack.length; } void myPrint(string Format, Args...)(auto ref Args args) { import core.stdc.stdio : printf; size_t parseFormat(string text, size_t offset) { if (text[offset + 1] == 's' || text[offset + 1] == 'c') return 1; else assert(0, "invalid format"); } void before(string text) { printf("%.*s", cast(int)text.length, text.ptr); } void actual(string Format3, T)(auto ref T value) { static if (is(T == string) && Format3[1] == 's') { printf("%.*s", cast(int)value.length, value.ptr); } else { printf(Format3.ptr, value); } } void handle(string Format2, size_t Arg)() { enum Offset = Format2.indexOf('%'); enum Length = Format2.length > Offset ? (parseFormat(Format2, Offset) + 1) : 0; static if (Offset <= Format2.length) { if (Offset > 0) before(Format2[0 .. Offset]); static if (Arg < Args.length) actual!(Format2[Offset .. Offset + Length])(args[Arg]); static if (Format2.length > Offset + Length) static if (Arg + 1 <= Args.length) handle!(Format2[Offset + Length .. $], Arg + 1); } else { // no format??? static assert(0, "Missing format for argument"); } } handle!(Format, 0); } extern(C) { void main() { import core.stdc.stdio : printf; myPrint!"b%s%ce\n"("Hellorld", '!'); printf("done\n"); } } ```
Mar 23









Ada <notemail not.com> 