What exactly are the String literrals in D and how they work?

jfondren julian.fondren at gmail.com
Sun Aug 15 08:40:26 UTC 2021


On Sunday, 15 August 2021 at 07:47:27 UTC, jfondren wrote:
> On Sunday, 15 August 2021 at 07:43:59 UTC, jfondren wrote:
>> On Sunday, 15 August 2021 at 06:10:53 UTC, rempas wrote:
>> ```d
>> unittest {
>>     char* s = "John".dup.ptr;
>>     s[0] = 'X'; // no segfaults
>>     assert(s[0..4] == "Xohn"); // ok
>> }
>> ```
>>
>>> So am I going to have an extra runtime cost having to first 
>>> construct a `string` and then ALSO cast it to a string 
>>> literal?
>
> In the above case, "John" is a string that's compiled into the 
> resulting executable and loaded into read-only memory, and this 
> code is reached that string is duplicated, at runtime, to 
> create a copy in writable memory.

Probably a more useful way to think about this is to consider 
what happens in a loop:

```d
void static_lifetime() @nogc {
     foreach (i; 0 .. 100) {
         string s = "John";
         // some code
     }
}
```

^^ At runtime a slice is created on the stack 100 times, with a 
pointer to the 'J' of the literal, a length of 4, etc. The cost 
of this doesn't change with the length of the literal, and the 
bytes of the literal aren't copied, so this code would be just as 
fast if the string were megabytes in length.

```d
void dynamically_allocated() { // no @nogc
     foreach (i; 0 .. 100) {
         char[] s = "John".dup;
         // some code
     }
}
```

^^ Here, the literal is copied into freshly GC-allocated memory a 
hundred times, and a slice is made from that.

And for completeness:

```d
void stack_allocated() @nogc {
     foreach (i; 0 .. 100) {
         char[4] raw = "John";
         char[] s = raw[0..$];
         // some code
     }
}
```

^^ Here, a static array is constructed on the stack a hundred 
times, and the literal is copied into the array, and then a slice 
is constructed on the stack with a pointer into the array on the 
stack, a length of 4, etc. This doesn't use the GC but the stack 
is limited in size and now you have worry about the slice getting 
copied elsewhere and outliving the data on the stack:

```d
char[] stack_allocated() @nogc {
     char[] ret;
     foreach (i; 0 .. 100) {
         char[4] raw = "John";
         char[] s = raw[0 .. $];
         ret = s;
     }
     return ret; // errors with -preview=dip1000
}

void main() {
     import std.stdio : writeln;

     char[] s = stack_allocated();
     writeln(s); // prints garbage
}
```


More information about the Digitalmars-d-learn mailing list