The usage of printf in D shouldn't be difficult to understand for C programmers. Smaller numeric types are promoted to int (32 bit) and double (64 bit) respectively. The "ll" modifier is used for 64-bit integers. See also Basic Data Types ( D 1.x, D 2.x).
For programmers without C background: the format specifier has the general form
%[-][w][.d][m]Fwhere all parts except the initial "%" and the final format character are optional. The typical values for F are: c (for single characters), s (for character strings), d (for most integer needs) and f (for most floating point needs).
The optional w specifies the overall width of the output, e. g.
printf("%6d",17); creates the output 17But be careful (within screen forms): if the field width is too small to hold the number the width will be increased automatically.
The optional .d specifies the number of decimals, e. g.
printf("%7.3f",3.14159); creates the output 3.142producing 2 leading blank2. The "." counts to the field width.
You can have the width w or the number of decimals d (or both) variable:
printf("%*d",6,17); creates the output 17Any "*" in the format string means that the value is passed as an int parameter in the printf parameter list.
printf("%.*f",1,3.14159); creates the output 3.1
int width=7; printf("%*.*f",width,2,3.14159); creates the output 3.14
You may eventually find yourself wondering why
The short answer is that D has a lot of good default things that make your life easier. The long answer is...
printf() is declared in object.d like this:
extern (C) - means that this is a C function, which is implemented in some other file (usually, in the standard library).
char* - means, of course, that the first argument (the format string) MUST be a char*.
... - means, like C, that this will accept any number of arguments (it is a varargs function).
In your first call:
The other magic that happens is that when you pass char into a function that expects char*, the compiler performs an implicit cast. So when you call
So, the argument that printf() sees is a pointer value which points to the start of the string; since D added an invisible zero at the end of the string, printf() terminates nicely. But try this, and it will break:
So why doesn't the compiler implicitly cast the array in the second call?
In this case, the compier doesn't know the type that printf() expects for the second argument. So it just passes the array onto the stack, unaltered.
So how do you print an arbitrary string in a portable manner? I use this code often:
So, in summary:
- The compiler adds nulls into the memory after constant strings, but when you build a string at runtime these nulls don't exist.
- The compiler implicitly casts char to char*, when it knows that this is necessary.
You have to be careful if you simply want to print a string, which may contain '%' characters.
to be safe. (also applies to writefln of course)
If you use writefln for this, you will get the error "invalid utf8-sequence".
However you may use printf, as the following code demonstrates:
If you want to send binary data to stdout, you still have to use a lower level function, which does not terminate on '\0'. Or you can write your own function, building on printf to print until '\0', and then send a zero-byte as a separate function call (single character).
(to be done)
Q: How to printf to stderr (instead of stdout)?
(a fully qualified name is used, because stderr could conflict with "stderr" from std.stdio (a "File"), if both imports are used)
ToDo: More examples. Special cases. ... Please add documentation of e as alternative to f for float, double and real.