www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Calling C functions that modify a string

reply Pat Maddox <pat patmaddox.com> writes:
Hi there, I want to call a C function that upcases a string. I 
have something working, I just want to check in here to see if 
there's a better approach that I'm missing. I ask because 
`std.string.toStringZ()` returns an `immutable char *`.

As far as I can tell, I have two options:

1. Make the extern definition accept immutable.
2. Cast to `char *`.

I opted for 2 because it seems that 1 would be confusing - the 
definition says immutable, but it mutates the string.

Anyway, is this the D way to mutate a string from C, or is there 
another approach I'm unaware of?

```
extern (C) void upcase(char *);

import std.stdio;
import std.string;

void main() {
   auto s = "hello d";
   auto cs = cast (char *) std.string.toStringz(s);
   upcase(cs);
   writeln(std.string.fromStringz(cs));
}
```

It also works with:

```
extern (C) void upcase(immutable char *);

import std.stdio;
import std.string;

void main() {
   auto s = "hello d";
   auto cs = std.string.toStringz(s);
   upcase(cs);
   writeln(std.string.fromStringz(cs));
}
```

but it seems that "immutable" is a lie in that case.
Jun 14 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/14/23 11:29 PM, Pat Maddox wrote:
 Hi there, I want to call a C function that upcases a string. I have 
 something working, I just want to check in here to see if there's a 
 better approach that I'm missing. I ask because `std.string.toStringZ()` 
 returns an `immutable char *`.
 
 As far as I can tell, I have two options:
 
 1. Make the extern definition accept immutable.
 2. Cast to `char *`.
 
 I opted for 2 because it seems that 1 would be confusing - the 
 definition says immutable, but it mutates the string.
 
 Anyway, is this the D way to mutate a string from C, or is there another 
 approach I'm unaware of?
 
 ```
 extern (C) void upcase(char *);
 
 import std.stdio;
 import std.string;
 
 void main() {
    auto s = "hello d";
    auto cs = cast (char *) std.string.toStringz(s);
    upcase(cs);
    writeln(std.string.fromStringz(cs));
 }
 ```
So interestingly enough, toStringz is pure, and returns an unrelated type, so you shouldn't need to cast. However, for some reason, it does require a cast. That seems like a bug to me.
 
 It also works with:
 
 ```
 extern (C) void upcase(immutable char *);
 
 import std.stdio;
 import std.string;
 
 void main() {
    auto s = "hello d";
    auto cs = std.string.toStringz(s);
    upcase(cs);
    writeln(std.string.fromStringz(cs));
 }
 ```
 
 but it seems that "immutable" is a lie in that case
Yeah, don't do it this way. just matching the type for a C prototype is very dangerous, especially if the C function doesn't obey the type constraints. Can I ask if this is a specific case of trying to use a C function to do "upper casing", or if this is a general question about C functions and modifying strings? Because we do have upper-casing facilities in both std.ascii and std.uni. But in general, if you want a mutable character array that's zero terminated, you need to make a copy with a zero terminator, but type it as mutable. I'm surprised there isn't a way to do this easily in the library. But if you need something that isn't wasteful, I would do something like this: ```d pure char *toMutStringz(const(char)[] str) { char[] result = str ~ "\0"; return result.ptr; } ``` -Steve
Jun 15 2023
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/15/23 9:18 AM, Steven Schveighoffer wrote:
 So interestingly enough, toStringz is pure, and returns an unrelated 
 type, so you shouldn't need to cast. However, for some reason, it does 
 require a cast. That seems like a bug to me.
Oh wait, a pure function can return immutable data that isn't allocated on the heap. Nevermind. -Steve
Jun 15 2023
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, June 15, 2023 7:18:06 AM MDT Steven Schveighoffer via 
Digitalmars-d-learn wrote:
 But in general, if you want a mutable character array that's zero
 terminated, you need to make a copy with a zero terminator, but type it
 as mutable. I'm surprised there isn't a way to do this easily in the
 library.
https://dlang.org/phobos/std_utf.html#toUTFz - Jonathan M Davis
Jun 15 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/15/23 10:04 AM, Jonathan M Davis wrote:
 On Thursday, June 15, 2023 7:18:06 AM MDT Steven Schveighoffer via
 Digitalmars-d-learn wrote:
 But in general, if you want a mutable character array that's zero
 terminated, you need to make a copy with a zero terminator, but type it
 as mutable. I'm surprised there isn't a way to do this easily in the
 library.
https://dlang.org/phobos/std_utf.html#toUTFz
Oh nice, so `toUTFz!char` should work. Thanks! -Steve
Jun 15 2023
parent reply bachmeier <no spam.net> writes:
On Thursday, 15 June 2023 at 15:53:57 UTC, Steven Schveighoffer 
wrote:
 On 6/15/23 10:04 AM, Jonathan M Davis wrote:
 On Thursday, June 15, 2023 7:18:06 AM MDT Steven Schveighoffer 
 via
 Digitalmars-d-learn wrote:
 But in general, if you want a mutable character array that's 
 zero
 terminated, you need to make a copy with a zero terminator, 
 but type it
 as mutable. I'm surprised there isn't a way to do this easily 
 in the
 library.
https://dlang.org/phobos/std_utf.html#toUTFz
Oh nice, so `toUTFz!char` should work. Thanks! -Steve
Shouldn't it be `toUTFz!(char*)`? That's what I've been using to pass strings to C after someone here recommended it.
Jun 15 2023
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/15/23 2:21 PM, bachmeier wrote:
 On Thursday, 15 June 2023 at 15:53:57 UTC, Steven Schveighoffer wrote:
 On 6/15/23 10:04 AM, Jonathan M Davis wrote:
 On Thursday, June 15, 2023 7:18:06 AM MDT Steven Schveighoffer via
 Digitalmars-d-learn wrote:
 But in general, if you want a mutable character array that's zero
 terminated, you need to make a copy with a zero terminator, but type it
 as mutable. I'm surprised there isn't a way to do this easily in the
 library.
https://dlang.org/phobos/std_utf.html#toUTFz
Oh nice, so `toUTFz!char` should work. Thanks!
Shouldn't it be `toUTFz!(char*)`? That's what I've been using to pass strings to C after someone here recommended it.
Yep. I didn't read so good... -Steve
Jun 15 2023