Recipe 16.10 Converting Pointers to a Byte[ ], SByte[ ],or Char[ ] to a String
Problem
You
have obtained a pointer to a
byte array, an sbyte array, or
a char array. You want to convert this array into
its string equivalent.
Solution
Use one of the string object's
constructors that build a string from either a
byte*, sbyte*, or
char* passed in as a parameter. The following
overloaded ConvertToString methods accept a
byte[], an sbyte[], or a
char[] and return the equivalent
string object created from these
arrays:
public string ConvertToString(byte[] arr)
{
unsafe
{
string returnStr;
fixed(byte* fixedPtr = arr)
{
returnStr = new string((sbyte*)fixedPtr);
}
}
return (returnStr);
}
public string ConvertToString(sbyte[] arr)
{
unsafe
{
string returnStr;
fixed(sbyte* fixedPtr = arr)
{
returnStr = new string(fixedPtr);
}
}
return (returnStr);
}
public string ConvertToString(char[] arr)
{
unsafe
{
string returnStr;
fixed(char* fixedPtr = arr)
{
returnStr = new string(fixedPtr);
}
}
return (returnStr);
}
The following code calls these methods, passing in one of the
required array types:
Console.WriteLine(ConvertToString(new byte[3] {0x61,0x62,0x63}));
Console.WriteLine(ConvertToString(new char[3] {'a','b','c'}));
Console.WriteLine(ConvertToString(new sbyte[3] {0x61,0x62,0x63}));
Discussion
The System.String constructor that takes an
sbyte* in the Solution code is expecting a
null-terminated string in the buffer. There are
also constructors on System.String that take an
sbyte* and default to Unicode, or allow you to
pass an Encoding object. One method to create a
string from these arrays is to use a foreach loop
to iterate over each element in the array and append the character
value of each array element to the end of a
StringBuilder object. However, this would operate
slower than using the technique in this recipe. In fact, assuming a
null-terminated string is in the byte array, the
following unsafe code to convert a byte array to a
string executes in 46% of the
time of its equivalent safe code:
public string ConvertToString(byte[] arr)
{
unsafe
{
string returnStr;
fixed(byte* fixedPtr = arr)
{
returnStr = new string((sbyte*)fixedPtr);
}
}
return (returnStr);
}
The safe code is shown here:
public string ConvertToStringSlow(byte[] arr)
{
System.Text.StringBuilder returnStr = new System.Text.StringBuilder( );
foreach (sbyte C in arr)
{
returnStr.Append(C);
}
return (returnStr.ToString( ));
}
In addition, the unsafe code is twice as fast as the following code,
which uses the Encoding.ASCII class to convert a
byte array to a
string:
public string ConvertToASCIIStringSlow(byte[] arr)
{
String retStr = Encoding.ASCII.GetString(arr);
return (retStr);
}
This recipe uses two overloaded string
constructors that accept either a pointer to a
byte array or a pointer to a
char array. The constructor then uses this array
to construct a string from the array. The newly created
string object is then initialized to this string
created from the array. The constructors used in this recipe are
defined as follows:
unsafe public String(char* value)
unsafe public String(sbyte* value)
The parameter for this constructor is defined as follows:
value
A pointer to either a char array or an
sbyte array.
Note that if a pointer to a byte array is passed
in, it must be cast to an sbyte:
returnStr = new string((sbyte*)fixedPtr);
Notice that the array's length is not passed in to
the string constructor. Instead, the constructor
will keep appending array values to the string until a
null character is reached. If you know how many
characters are in the array, then you should use the string overload
that allows you to pass in the length.
See Also
See the "Unsafe Code Tutorial" and
the "Encoding Class" topics in the
MSDN
documentation.
|