Last update March 7, 2012

How To /
printf



Difference (last change) (no other diffs, normal page display)

Deleted: 190,300d189
jam tangan
jam tangan murah
jam tangan kw
hostgator coupon
kata mutiara
Jasa SEO
EZido
RDAnet
pioneer deh-1300mp
asus a53e-xa2
asus tf101-b1
asus tf101-a1
asus n53sv-eh72
asus republic of gamers g74sx
asus acer a5250
acer chromebook ac700
asus asus 53u
lg infinia 55lw5600
Sonicview 360 premier
asus 7 cu ft freezer
asus 30 single wall oven
brother cs6000i sewing machine
brother 1034d serger
brother sewing machines
Yokohama Geolandar H/T-S
crib tent tots in mind
kidco peapod plus
foscam fi8910w
samsung pl120 review
gopro helmet cam
Canon SX130IS
powershot s100
ContourHD 1080p
canon vixia hf r21
digital picture frame
canon ef 50mm f1.4
canon ef 70-300mm review
wide angle lenses
moving comfort sports bra
moving comfort bra
womens argyle sweater
bebe dresses
ViewSonic VX2250WM
Le Pan TC 970
Apple MacBook Air MC965LL
Sennheiser CX 880
plantronics cs540
ultrasonic jewelry cleaner
Sennheiser RS120
bose quietcomfort 15 acoustic noise cancelling headphones
logitech harmony one remote
logitech harmony 900
sony mhc-ec69i
sony mhcec909ip
bose wave music system
sony htss380
logitech squeezebox touch
sony dvp-fx970
onkyo tx-nr509
onkyo tx - nr609
onkyo ht-s3400
energy 5.1 take classic home theater system
polk audio psw505
onkyo ht-s5400
onkyo tx-nr709
belkin pf60
onkyo ht-rc360
denon avr-1912
Yamaha YHT-S400BL
fujitsu scansnap s1500
brother hl-2270dw
epson workforce 545
hp laserjet p2055dn
bushnell 8mp trophy cam
toshiba 32c110u
panasonic viera tc-p60s30
VIZIO E220VA
hauppauge wintv dcr-2650
Acer AM3970-U5022
Acer AspireRevo AR3700-U3002
Dell Inspiron i570
Dell GX620
Gateway FX6860-UR20P
Western Digital My Passport Essential SE 1 TB USB 3.0
Fujitsu ScanSnap S1300
Epson Perfection V300
Fujitsu SCANSNAP S1100
NeatDesk Desktop Scanner and Digital Filing System
Epson WorkForce Pro GT-S50
Kodak P811BK
Epson Perfection V330
Viewsonic VX2453MH
Asus VE228H
ViewSonic VA2431WM
Samsung B2230
HP 2711x
ASUS ML228H
Epson PowerLite Home Cinema 8350
Optoma PK301
Epson EX7210
Epson EX5210
ViewSonic PJD5133
Acer X1161P
FAVI RioHD-LED-2
Epson EX3210
ViewSonic PJD6531w
Trinity 360 Breville 800JEXL
Skil 3320-02
Delta 46-460
Grizzly G0555
Delta 18-900L

Table of contents of this page
Overview   
Specifier   
char[] vs. char*   
Be careful when only printing a string   
printing non-utf8 encoded strings (e.g. latin1)   
sending raw bytes to stdout (for binary data)   
printf to stderr   
To Do   

Overview    

NOTE: D now has a typesafe alternative to printf, called writeln. Use 'import std.stdio' to access it. In general, you should use that instead of printf. However, printf might be useful, for example to print raw bytes, instead of utf8-strings to the terminal.

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).

Specifier    

data typeformat specifieralternativescomments
bit byte short int enum%d%x (hex) 
ubyte ushort uint%u%x (hex) 
long%lld%llx (hex) 
ulong%llu%llx (hex) 
cent  not yet implemented
ucent  not yet implemented
float ifloat double idouble%lf%f 
real ireal%Lf  
cfloat cdouble%lf + %lfi(%f %f)using "i" or parentheses (you can also print separately using the .re .im properties of complex values)
creal?  
char%c%d (integer) %x (hex) 
wchar?%d (integer) %x (hex) 
char []%.*s passed as (count + pointer)
wchar []?  
pointer%p  

For programmers without C background: the format specifier has the general form

    %[-][w][.d][m]F
where 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  
        17
But 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.142
producing 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  
        17

printf("%.*f",1,3.14159); creates the output 3.1

int width=7; printf("%*.*f",width,2,3.14159); creates the output 3.14

Any "*" in the format string means that the value is passed as an int parameter in the printf parameter list.

char[] vs. char*    

You may eventually find yourself wondering why

printf(std.compiler.name);
works while
printf("%.*s\n", std.compiler.name);
doesn't. A C-library printf() will be expecting that the format string (the first argument) is a null-terminated string. But if D doesn't null-terminate strings, and if arrays are actually two numbers (length and pointer), then how can it work?

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) int printf(char *, ...);

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:

printf(std.compiler.name);
std.compiler.name is defined in std/compiler.d as:
char[] name = "Digital Mars D";
That is, the type is a dynamic array, but it is initialized with a certain constant string. When you use constant strings like this, D automatically places a zero byte after the string. It doesn't count in the length of the array, but a C function that reads the array will see the zero terminator it expects.

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

printf(std.compiler.name);
this implicit cast happens:
printf(cast(char*)std.compiler.name);
which basically means this is happening:
printf(&std.compiler.name[0]);

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:

printf("std.compiler.name = "~std.compiler.name);
When you concatenate the two arrays with the ~ operator, the compiler makes a copy of the two and returns the concatenated string in a new array someplace. This operation does NOT get the automatic null terminator. So printf will run off forever, printing garbage, until it hits a 0 by pure luck or until you get an Access Violation (segfault).

So why doesn't the compiler implicitly cast the array in the second call?

printf("%s\n", std.compiler.name);

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.

printf("%s\n", std.compiler.name);
is more or less the same as calling this:
printf("%s\n", std.compiler.name.length, cast(char*)std.compiler.name);
Your choices are to use the %.s, or to use this:
printf("%s\n", cast(char*)std.compiler.name);
The %.s is probably better in most cases, but not all C libraries support it. The cast is supported everywhere, but doesn't work if the string isn't null terminated.

So how do you print an arbitrary string in a portable manner? I use this code often:

char[] foo;
printf("%s\n", cast(char*)(foo~\0));
which just appends a null character onto the string, then casts the string to a char* so that printf() gets what it expects. Happily, D's runtime library provides the toStringz() function in std.string which does the same:
char[] foo;
printf("%s\n", toStringz(foo));
...plus Walter's function has some smarts in it to avoid doing unneccesary copies.

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.
Source: based on NG:D/26472

Be careful when only printing a string    

You have to be careful if you simply want to print a string, which may contain '%' characters.

Use:

string s;
writefln("%s", s);
printf("%.*s", s);

to be safe. (also applies to writefln of course)

printing non-utf8 encoded strings (e.g. latin1)    

If you use writefln for this, you will get the error "invalid utf8-sequence".

However you may use printf, as the following code demonstrates:

import std.stdio;
string s; //char[]
for (int i=32; i<255; i++) {
  s~=i;
  if (s.length%32==0) s~='\n';
}
printf("%.*s\n", s); //ok
//writefln("%s", s); //error: "invalid utf8-sequence"

sending raw bytes to stdout (for binary data)    

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)

printf to stderr    

Q: How to printf to stderr (instead of stdout)?

A: Use:

//import std.c.stdio; //"stderr" symbol, for use with fprintf
fprintf(std.c.stdio.stderr, "%.*s\n", s); //ok in D1+D2

(a fully qualified name is used, because stderr could conflict with "stderr" from std.stdio (a "File"), if both imports are used)

To Do    

ToDo: More examples. Special cases. ... Please add documentation of e as alternative to f for float, double and real.


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: March 7, 2012 20:40 (diff))