Mario The Spoon
Mario The Spoon

Reputation: 4869

C# convert byte[] containing a c-style string to string - NOT Encoding.GetString(byte[])

stupid me tries to convert a byte-array received from an external source not unter my control to a string. (And yes, I do know about Encoding.GetString(byte[]).

What I have so far:

void myfunc()
{
    byte[] rawData = new byte[ 128 ];

    for( int i = 0; i < rawData.Length; ++i )
    {
        rawData[ i ] = 0;
    }

    rawData[ 0 ] = (byte)'H';
    rawData[ 1 ] = (byte)'e';
    rawData[ 2 ] = (byte)'l';
    rawData[ 3 ] = (byte)'l';
    rawData[ 4 ] = (byte)'o';


    string asString = Encoding.UTF8.GetString( rawData, 0, rawData.Length );

    string asRealString = Encoding.UTF8.GetString( rawData );
}

Both strings do contain the Hello part but also a lot of \0's afterwards - which is not the thing I expected. The output from the debugger: asRealString =

"Hello\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

Is there any way that would geive me a string like "Hello" ?

I did goolge,but all I got was Encoding.GetString(byte[]) ...

EDIT: The creatin of the byte array is outside my scope! I do get it as part of a larger, C-Style struct. And there is no leading length of the string. Also I was hoping there iss ome built in way to tdo it and I did not have to find the first \o and tehn convert knowing the length....

EDIT Here is what I used in the end:

private static string convertCString( byte[] buffer, int maxLength, Encoding targetEncoding )
{
    int length = 0;
    int realMax = buffer.Length < maxLength ? buffer.Length : maxLength;

    for( 
         ; 0 != buffer[length] && length < realMax
         ; ++length )
    {}

    return targetEncoding.GetString( buffer, 0, length );
}

Upvotes: 5

Views: 5110

Answers (7)

Stephen Cleary
Stephen Cleary

Reputation: 457127

The creatin of the byte array is outside my scope! I do get it as part of a larger, C-Style struct. And there is no leading length of the string.

It may be possible to do this in a built-in way by having the marshaller do it for you.

I'm assuming that what you have now is like:

struct CStruct
{
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)]
  public byte[] data;
}

Try changing it to:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct CStruct
{
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
  public string data;
}

Upvotes: 2

Viacheslav Smityukh
Viacheslav Smityukh

Reputation: 5843

void myfunc()
{
    byte[] rawData = new byte[ 128 ];

    //CLR will initialize each elemnet in arry to the 0
    //for( int i = 0; i < rawData.Length; ++i )
    //{
    //    rawData[ i ] = 0;
    //}

    rawData[ 0 ] = (byte)'H';
    rawData[ 1 ] = (byte)'e';
    rawData[ 2 ] = (byte)'l';
    rawData[ 3 ] = (byte)'l';
    rawData[ 4 ] = (byte)'o';

    // you should know length of the received string (each IO read method return number of read bytes), if you don't know it you can try to search 0 as the EOS
    var receivedBytes = Array.IndexOf(rawData, 0);
    string asString = Encoding.ASCII.GetString( rawData, 0, receivedBytes );
}

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1063824

Just find the first 0:

    int len = Array.IndexOf(rawData, (byte)0); // maybe some bounds check too
    string asString = Encoding.UTF8.GetString(rawData, 0, len);

Upvotes: 13

leppie
leppie

Reputation: 117310

new string(Array.ConvertAll(rawData, x => (char)x))

The string constructor will terminate the string at the first \0.

Upvotes: 0

Joel Etherton
Joel Etherton

Reputation: 37543

Why didn't you expect that? You explicitly told it to do that to start with:

byte[] rawData = new byte[ 128 ];

for( int i = 0; i < rawData.Length; ++i )
{
    rawData[ i ] = 0;   // RIGHT HERE
}

The above code creates a 128 item byte array and the for loop populates it. Then your code explicitly changes the value of the first 5 bytes. If you don't want to see the \0, then you need either not to put it there or exclude it from the array before sending it to GetString.

Upvotes: 1

Antony Woods
Antony Woods

Reputation: 4472

When you do

string asString = Encoding.UTF8.GetString( rawData, 0, rawData.Length );

Instead of passing in rawData.Length, can you not just pass in the actual length of the string?

Upvotes: 0

Aliostad
Aliostad

Reputation: 81690

Try

Encoding.UTF8.GetString( rawData ).Trim();

Upvotes: 2

Related Questions