Thread overview
Calling C functions that modify a string
Jun 15, 2023
Pat Maddox
Jun 15, 2023
Jonathan M Davis
Jun 15, 2023
bachmeier
June 15, 2023

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.

June 15, 2023

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:

pure char *toMutStringz(const(char)[] str)
{
   char[] result = str ~ "\0";
   return result.ptr;
}

-Steve

June 15, 2023

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

June 15, 2023
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



June 15, 2023

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

June 15, 2023

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.

June 15, 2023
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