Compile time format string check
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Mon Mar 23 08:02:39 UTC 2026
On 23/03/2026 8:13 PM, Ada wrote:
> On Monday, 23 March 2026 at 05:46:15 UTC, Richard (Rikki) Andrew
> Cattermole wrote:
>> On 23/03/2026 6:36 PM, Ada wrote:
>>> On Monday, 23 March 2026 at 05:33:05 UTC, Richard (Rikki) Andrew
>>> Cattermole wrote:
>>>> On 23/03/2026 6:29 PM, Ada wrote:
>>>>> On Sunday, 22 March 2026 at 22:49:24 UTC, Richard (Rikki) Andrew
>>>>> Cattermole wrote:
>>>>>> [...]
>>>>>
>>>>> 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)
>>>>
>>>> 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.
>>>
>>> In that case, how would you do it with the pragma or the template
>>> parameter?
>>
>> 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.
>
> 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?
No.
> 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");
}
}
```
More information about the Digitalmars-d-learn
mailing list