@@ -217,7 +217,7 @@ $(ITEM q4, Why is printf in D?)
217
217
is not part of D, it is part of C's standard
218
218
runtime library which is accessible from D.
219
219
D's standard runtime library has
220
- $(REF writefln , std,stdio)
220
+ $(REF writef , std,stdio)
221
221
which is as powerful as $(LINK2 http://www.digitalmars.com/rtl/stdio.html#printf, printf)
222
222
but is much easier to use.
223
223
)
@@ -381,43 +381,70 @@ void main()
381
381
382
382
$(ITEM printf, How do I get printf() to work with strings?)
383
383
384
- In C, the normal way to printf a string is to use the $(B %s)
385
- format:
384
+ $(P In C, the normal way to printf a string is to use the $(D %s)
385
+ format:)
386
386
387
387
$(CCODE
388
388
char s[8];
389
389
strcpy(s, "foo");
390
390
printf("string = '%s'\n", s);
391
391
)
392
392
393
- Attempting this in D, as in:
393
+ $(P Attempting this in D:)
394
394
395
+ $(RUNNABLE_EXAMPLE_FAIL
395
396
---------------------------------
397
+ import core.stdc.stdio;
396
398
string s;
397
399
s = "foo";
398
- printf("string = '%s'\n", s);
400
+ printf("string = '%s'\n", s); // Error
399
401
---------------------------------
400
-
401
- usually results in garbage being printed, or an access violation.
402
- The cause is that in C, strings are terminated by a 0 character.
403
- The $(B %s) format prints until a 0 is encountered.
404
- In D, strings are not 0 terminated, the size is determined
402
+ )
403
+ $(P The call gets flagged at compile-time (see
404
+ $(DDSUBLINK spec/pragma, printf, `pragma(printf)`))
405
+ because in general, `string` is not compatible with the `%s` specifier.
406
+ This prevents garbage being printed, or an access violation.)
407
+
408
+ $(P In D, a string is an array, so it has a length and a pointer.
409
+ In C, a string is a pointer to memory terminated by a 0 character.
410
+ The $(D %s) format prints until a 0 is encountered.
411
+ In D, strings in general are not 0-terminated, the size is determined
405
412
by a separate length value. So, strings are printf'd using the
406
- $(B %.*s) format:
413
+ $(D %.*s) format:)
407
414
415
+ $(RUNNABLE_EXAMPLE
408
416
---------------------------------
417
+ import core.stdc.stdio;
409
418
string s;
410
419
s = "foo";
411
- printf("string = '%.*s'\n", s );
420
+ printf("string = '%.*s'\n", cast(int) s.length, s.ptr );
412
421
---------------------------------
422
+ )
423
+ $(P which will behave as expected, for that input data.
424
+ There are pitfalls:)
425
+ * printf's $(D %.*s) will print until the length
426
+ is reached or a 0 is encountered, so D strings with embedded 0's
427
+ will only print up to the first 0.
428
+ * printf's length argument is an int, so ensure `s.length <= int.max`.
429
+
430
+ $(P D string literals are actually 0-terminated, so `%s` can be used
431
+ with the `.ptr` property and printf will work for those.
432
+ However, non-literal strings often are not 0-terminated:)
433
+
434
+ $(RUNNABLE_EXAMPLE
435
+ ---
436
+ import core.stdc.stdio;
437
+ printf("string = '%s'\n", "bar".ptr); // OK, 0-terminated
438
+
439
+ string s = "food";
440
+ s = s[0..3]; // foo, not 0-terminated
441
+ printf("string = '%.*s'\n", cast(int) s.length, s.ptr);
413
442
414
- $(P which will behave as expected.
415
- Remember, though, that printf's $(B %.*s) will print until the length
416
- is reached or a 0 is encountered, so D strings with embedded 0's
417
- will only print up to the first 0.
443
+ s ~= "ie"; // s is still not 0-terminated
444
+ ---
418
445
)
419
446
420
- $(P Of course, the easier solution is just use $(REF writefln , std, stdio)
447
+ $(P Of course, the easier solution is just to use $(REF writef , std, stdio)
421
448
which works correctly with D strings.
422
449
)
423
450
0 commit comments