String* to char[]

P

Peteroid

How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;
char m_char_array[32+1] ;

m_char_array = my_string ; // error
strcpy( m_char_array, my_string ) ; // error
strcpy( m_char_array, my_string.ToCharArray( ) ) ; // error
strcpy( m_char_array, my_string.ToCharArray(0,32 ) ) ; // error
strcpy( m_char_array, my_string.ToCharArray(0,0) ) ; // error

Thanks in advance! : )

[==Peteroid==]
 
W

William DePalo [MVP VC++]

Peteroid said:
How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;
char m_char_array[32+1] ;
...

First pin the sting object (prevent it from being moved by the GC), and get
a pointer to the first character of the string

#include <vcclr.h>

wchar_t __pin *p = PtrToStringChars(my_string);

then for as many characters as you have got, copy them to the target

Regards,
Will
 
P

Peteroid

Hi Will,

Thanks for the reply. The following line:

wchar_t __pin *p = PtrToStringChars(my_string);

now generates the error: "p is an undeclared indentifier (error C2065)". I
did include the 'vcclr.h' include. I've never used pinning before, though I
vaguely know what it's for (GC can move things around in memory, pin
prevents this, just not sure yet when this is necessary and when it isn't).
Also, I'm trying to get the result into a char[33] array, so is wchar_t*
compatible with this for direct copying?

Also, when you say 'copy them to target' (i.e., the char[33] variable) could
you give me an idea how to do this (e.g., use strcpy?). Thanks again! :)

[==Peteroid==]

PS - It's weird that String* my_string = "HELLO" ; works (i.e. direct
assignment from a char string to a String) but the reverse doesn't (probably
because char came before String* in C(++) laguage development). But it
really shouldn't be this complicated to get a char[] copied to a String
(IMHO), as the requirement for such a conversion to make old code using
char[] more easily modernizable (i.e., String should have come with a built
in conversion tool, which I thought was the purpose of ToCharArray() (which
seems to not do what it looks like it should be doing, as what it outputs
does not act like a char[])...

William DePalo said:
Peteroid said:
How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;
char m_char_array[32+1] ;
...

First pin the sting object (prevent it from being moved by the GC), and
get a pointer to the first character of the string

#include <vcclr.h>

wchar_t __pin *p = PtrToStringChars(my_string);

then for as many characters as you have got, copy them to the target

Regards,
Will
 
C

Carl Daniel [VC++ MVP]

Peteroid said:
How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;

HGLOBAL hg = (HGLOBAL)System::Marshal::StringToHGlobalAnsi(my_string);
char* p = GlobalLock(hg);

// work with p - it's an ordinary pointer to zero-terminated string

GlobalFree(hg);

-cd
 
G

Guest

I think you mean

System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(my_string);

mosimu

Carl Daniel said:
Peteroid said:
How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;

HGLOBAL hg = (HGLOBAL)System::Marshal::StringToHGlobalAnsi(my_string);
char* p = GlobalLock(hg);

// work with p - it's an ordinary pointer to zero-terminated string

GlobalFree(hg);

-cd
 
I

Ioannis Vranos

Peteroid said:
How the heck does one convert a String* to char[]? Specifically:

String* my_string = "HELLO" ;
char m_char_array[32+1] ;


String contains wchar_ts. You may use String::ToCharArray and copy
wchar_t character by character to a wstring, using wstring::push_back().
 
W

William DePalo [MVP VC++]

Peteroid said:
I've never used pinning before, though I vaguely know what it's for (GC
can move things around in memory, pin prevents this, just not sure yet
when this is necessary and when it isn't).

Well, on the managed side of things you needn't worry about it. The .Net
Platform exists so that developers don't have to work about such things if
they don't want. (We'll agree to table the discussion as to when memory
pressure might become an issue in managed code <g>). However, anytime you
cross the boundary and play in an unmanaged space you have to pin things.
That's because it is possible that the GC can move or reclaim an object
rendering your pointer quite stale. As Martha might say, that would be a bad
thing.
Also, I'm trying to get the result into a char[33] array, so is wchar_t*
compatible with this for direct copying?

Well, no. Net strings are composed of 16 bit characters.
Also, when you say 'copy them to target' (i.e., the char[33] variable)
could you give me an idea how to do this (e.g., use strcpy?). Thanks
again! :)

Actually, it would take sonmething like wcstombs() to transform 16 bit
characters to 8 bit characters.

Carl offered another approach which allocates a unmanaged array of ANSI
characters. You do need to remember to free the handle when you are done or
a memory leak results. For the odd transition into unmanaged code I doubt
that performance implications of the heap allocations are a consideration.
If you are doing a lot of transitions you might want to profile which
approach costs less.

Regards,
Will
 
I

Ioannis Vranos

Ioannis said:
String contains wchar_ts. You may use String::ToCharArray and copy
wchar_t character by character to a wstring, using wstring::push_back().


Or better:


#using <mscorlib.dll>

#include <string>

int main()
{
using namespace std;
using namespace System;

String *S= __gc new String("Some string");

wchar_t __pin *temp= &(S->ToCharArray())[0];

wchar_t *p=temp;

wstring s(p, p+3);

temp=0;
}
 
I

Ioannis Vranos

Why this shouldn't work?


#using <mscorlib.dll>

#include <string>

int main()
{
using namespace std;
using namespace System;

String *S= __gc new String("Some string");

wchar_t __pin *temp= &(S->ToCharArray())[0];

wchar_t *p=temp;

wstring s(p, p+3);

temp=0;
}
 
I

Ioannis Vranos

Ioannis said:
#using <mscorlib.dll>

#include <string>

int main()
{
using namespace std;
using namespace System;

String *S= __gc new String("Some string");

wchar_t __pin *temp= &(S->ToCharArray())[0];

wchar_t *p=temp;

wstring s(p, p+3);

temp=0;
}


I used *p, because there is some bug in VC++ 2003 that doesn't compile
wstring s(temp, temp+3); directly. In VC++ 2005 Beta however it works
and with the new C++/CLI syntax it becomes:


#include <string>

int main()
{
using namespace std;
using namespace System;

String ^S= gcnew String("Some string");

pin_ptr<wchar_t> pinp= &(S->ToCharArray())[0];

wstring s(pinp, pinp+3);

pinp=nullptr;
}
 
P

Peteroid

Yes, i did something very similar:

char char_array[32+1] ;
String* string_thing = new String("Hello") ;

for ( int c=0 ; c < length ; c++)
{
char_array[c] = char(string_thing->chars[c]) ;
}

char_array[length] = '\0' ;


After this code is executed: char_array contains null-terminated "Hello".

Thanx for everyones help! my code now works... :)

[==Peteroid==]

Ioannis Vranos said:
Why this shouldn't work?


#using <mscorlib.dll>

#include <string>

int main()
{
using namespace std;
using namespace System;

String *S= __gc new String("Some string");

wchar_t __pin *temp= &(S->ToCharArray())[0];

wchar_t *p=temp;

wstring s(p, p+3);

temp=0;
}
 
P

Peteroid

After looking my code over again, I'm wondering if I have to 'pin'
string_thing down during the character-by-character assignment loop.

My code so far has worked without doing this, but as I understand it this is
one of those things where it can bite you at random times based on the
current (and sometimes recent past) situation (i.e., depends on if GC
decides to move it at an inappropriate time or not).

On the other hand, it might be the case that i'm guaranteed that as long as
I stay in the same process (i.e. the same event process) that it can't
change. That is, I don't know if during my execution of the processing of a
single event if my code can be interrupted at any time and this GC object
(i.e., String*) then moved (which could be the whole reason for pinning,
which like I've said, is new to me...hehe).

If I need to do pinning, please tell me so, and possibly modify my code
(below from previous message) to include the pinning. Thanks!

[==Peteroid==]

Peteroid said:
Yes, i did something very similar:

char char_array[32+1] ;
String* string_thing = new String("Hello") ; int length = String->Length ;

for ( int c=0 ; c < length ; c++)
{
char_array[c] = char(string_thing->chars[c]) ;
}

char_array[length] = '\0' ;


After this code is executed: char_array contains null-terminated "Hello".

Thanx for everyones help! my code now works... :)

[==Peteroid==]

Ioannis Vranos said:
Carl said:
System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(my_string);


Why this shouldn't work?


#using <mscorlib.dll>

#include <string>

int main()
{
using namespace std;
using namespace System;

String *S= __gc new String("Some string");

wchar_t __pin *temp= &(S->ToCharArray())[0];

wchar_t *p=temp;

wstring s(p, p+3);

temp=0;
}
 
W

William DePalo [MVP VC++]

Peteroid said:
After looking my code over again, I'm wondering if I have to 'pin'
string_thing down during the character-by-character assignment loop.

No, you don't. If understand correctly, you are spinning a loop in managed
code and accessing a property of a managed object. Whaddya gotta pin, there?
<G>

You need to pin a pointer when you have to convert from a __gc pointer to a
__nogc pointer. __gc pointers point to objects that cam be moved by the
grbage collector. __nogc pointers don't know about the existence of the
grabage collector. They must remain fixed. That's what pinning does.

Regards,
Will
 
I

Ioannis Vranos

Peteroid said:
Yes, i did something very similar:

char char_array[32+1] ;


Why use a char array and not a std::wstring which is the natural for
this, or even std::string?

String* string_thing = new String("Hello") ;

for ( int c=0 ; c < length ; c++)
{
char_array[c] = char(string_thing->chars[c]) ;


Besides the correct string_thing->Length that should be used, casting is
not needed here.
 
I

Ioannis Vranos

Peteroid said:
After looking my code over again, I'm wondering if I have to 'pin'
string_thing down during the character-by-character assignment loop.


No pinning is not needed here. You have to pin only when you are doing
pointer arithmetic on managed types (*p++, etc).
 
I

Ioannis Vranos

Ioannis said:
No pinning is not needed here. You have to pin only when you are doing
pointer arithmetic on managed types (*p++, etc).


And not pointer arithmetic only. Also when you point to or access any
part of a managed type with an unmanaged pointer.
 
G

Guest

Is it safe to write to the the pinned string pointer? Say you call
GetComputerName. Can you pin a String object that is large enough and pass
its LPWSTR to GetComputerName to eliminate the memory copy? Is this legal
with VC2005? It seems PtrToStringChars returns a _const_Char_ptr. Is that to
keep people from writing directly into the String object? Is not there a way
to do it with StringBuilder? Otherwise it seems DllImport can be more
efficient than IJW when calling this type of API.
 
I

Ioannis Vranos

RC said:
Is it safe to write to the the pinned string pointer?

If you are talking about System::String, no. System::String is an
immutable String type, and also it is a high-level type, so if you use a
String object, you had better use its methods, properties, etc.


Say you call
GetComputerName. Can you pin a String object that is large enough and pass
its LPWSTR to GetComputerName to eliminate the memory copy?


I do not know what LPWSTR is, and thus I cannot answer this.

Is this legal
with VC2005?


In C++/CLI you can only pin value types (value classes,managed arrays of
built in types etc).



It seems PtrToStringChars returns a _const_Char_ptr. Is that to
keep people from writing directly into the String object? Is not there a way
to do it with StringBuilder?


You can also convert a StringBuilder to a managed wchar_t array, if this
was your question about.


Otherwise it seems DllImport can be more
efficient than IJW when calling this type of API.


I only know ISO C++ and .NET.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top