Welcome to Web-News
A Web-based News Reader
Subject Re: [Beginner] My first program - Access Violation :-(
From Russ Lewis <spamhole-2001-07-16@deming-os.org>
Date Thu, 25 Mar 2004 22:16:00 -0700
Newsgroups D

J Anderson,
What you've explained so far is correct; I just wanted to add a bit to it.

Dave,
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 Walter has put in 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,
Walter automatically places a null 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 null 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((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 Walter added an invisible null 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,
                       (char*)std.compiler.name);
Your choices are to use the %.s, or to use this:
        printf("%s\n", (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", (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,
Walter 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


Recent messages in this thread
 
-# [Beginner] My first program - Access Violation :-( Dave Sieber 25-Mar-2004 07:51 pm
.-# Re: [Beginner] My first program - Access Violation :-( J Anderson 25-Mar-2004 07:55 pm
..-# Re: [Beginner] My first program - Access Violation :-( J Anderson 25-Mar-2004 08:02 pm
..|-# Re: [Beginner] My first program - Access Violation :-( Dave Sieber 25-Mar-2004 09:01 pm
..||-# Re: [Beginner] My first program - Access Violation :-( SL 25-Mar-2004 09:21 pm
..||.\# Re: [Beginner] My first program - Access Violation :-( Dave Sieber 25-Mar-2004 09:47 pm
..|-# Re: [Beginner] My first program - Access Violation :-( (Current message) Russ Lewis 26-Mar-2004 12:16 am
..|.-# Re: [Beginner] My first program - Access Violation :-( Dave Sieber 26-Mar-2004 01:53 am
..|..\# Re: [Beginner] My first program - Access Violation :-( J Anderson 26-Mar-2004 02:32 am
..-# Re: [Beginner] My first program - Access Violation :-( Brad Anderson 25-Mar-2004 08:37 pm
...\# Re: [Beginner] My first program - Access Violation :-( Dave Sieber 25-Mar-2004 09:02 pm