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

jfondren julian.fondren at gmail.com
Sun Aug 15 07:43:59 UTC 2021


On Sunday, 15 August 2021 at 06:10:53 UTC, rempas wrote:
> So when I'm doing something like the following: `string name = 
> "John";`
> Then what's the actual type of the literal `"John"`?

```d
unittest {
     pragma(msg, typeof("John"));  // string
     pragma(msg, is(typeof("John") == immutable(char)[]));  // true
}
```

> In the chapter [Calling C 
> functions](https://dlang.org/spec/interfaceToC.html#calling_c_functions) in the "Interfacing with C" page, the following is said:
>> Strings are not 0 terminated in D. See "Data Type 
>> Compatibility" for more information about this. However, 
>> string literals in D are 0 terminated.

```d
void zerort(string s) {
     assert(s.ptr[s.length] == '\0');
}

unittest {
     zerort("John"); // assertion success
     string s = "Jo";
     s ~= "hn";
     zerort(s); // assertion failure
}
```

If a function takes a string as a runtime parameter, it might not 
be NUL terminated. This might be more obvious with substrings:

```d
unittest {
     string j = "John";
     string s = j[0..2];
     assert(s == "Jo");
     assert(s.ptr == j.ptr);
     assert(s.ptr[s.length] == 'h'); // it's h-terminated
}
```

>
> Which is really interesting and makes me suppose that `"John"` 
> is a string literal right?
> However, when I'm writing something like the following: `char 
> *name = "John";`,
> then D will complain with the following message:
>> Error: cannot implicitly convert expression `"John"` of type 
>> `string` to `char*`
>
> Which is interesting because this works in C.

Well, kinda:

```c
void mutate(char *s) {
     s[0] = 'X';
}

int main() {
     char *s = "John";
     mutate(s); // segmentation fault
}
```

`char*` is just the wrong type, it suggests mutability where 
mutability ain't.

> If I use `const char*` instead, it will work. I suppose that 
> this has to do with the fact that `string` is an alias for 
> `immutable(char[])` but still this has to mean that the actual 
> type of a LITERAL string is of type `string` (aka 
> `immutable(char[])`).
>
> Another thing I can do is cast the literal to a `char*` but I'm 
> wondering what's going on under the hood in this case.

The same thing as in C:

```d
void mutate(char *s) {
     s[0] = 'X';
}

void main() {
     char* s = cast(char*) "John";
     mutate(s); // program killed by signal 11
}
```

> Is casting executed at compile time or at runtime?

Compile-time. std.conv.to is what you'd use at runtime. Here 
though, what you want is `dup` to get a `char[]`, which you can 
then take the pointer of if you want:

```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?
>
> I hope all that makes sense and the someone can answer, lol




More information about the Digitalmars-d-learn mailing list