C#: Converting String to Sbyte* - c#

My C# code uses a Managed C++ Wrapper. To make a new object of this Wrapper's type, I need to convert String's to Sbyte*'s. A few StackOverflow.com posts discussed how to convert String to byte[], as well as byte[] to sbyte[], but not String to sbyte*.
msdn.social.com offers advice on how to convert a byte array to a string:
> // convert String to Sbyte*
> string str = "The quick brown, fox jumped over the gentleman.";
>
> System.Text.ASCIIEncoding encoding = new
> System.Text.ASCIIEncoding();
>
> Byte[] bytes = encoding.GetBytes(str);
However, "bytes" is not of type sbyte*. My following attempts to convert bytes to sbyte* failed:
1. Convert.ToSbyte(bytes);
2. cast: (sbyte*) bytes;
Please advise me on how to convert a C# string to an sbyte*.
Also, please talk about any side effects from introducing sbyte*, which I believe is unsafe code.
Thanks,
Kevin

Hmmm how about something like this:
(didnt test it, dont give me -1 if it doesnt work, I just believe that it should) :))
string str = "The quick brown fox jumped over the gentleman.";
byte[] bytes = Encoding.ASCII.GetBytes(str);
unsafe
{
fixed (byte* p = bytes)
{
sbyte* sp = (sbyte*)p;
//SP is now what you want
}
}

You can do that way:
sbyte[] sbytes = Array.ConvertAll(bytes, q => Convert.ToSByte(q));

sbyte[] and sbyte* are almost the same thing (almost)
sbyte[] str1;
sbyte* str2;
&str1[0] is a pointer to the first element of the array of chars
str2 is a pointer to a char, which presumably has a bunch of consecutive chars following it, followed by a null terminator
if you use str1 as an array, you know the length without a null terminator. but if you want to pass str1 to a string api that requires sbyte*, you use &str1[0] to turn it into a sbyte*, and then you stripped away array length information, so you have to make sur eyou're null terminated.
Cipi's answer shows you how to convert an array to a pointer, C# makes it hard to use pointers, on purpose. in C or C++ arrays and pointers are similar.
http://www.lysator.liu.se/c/c-faq/c-2.html
http://pw1.netcom.com/~tjensen/ptr/pointers.htm

Related

Convert c++ char array to c# string

I have a struct in C++ which has a char[10] field.
struct Package
{
char str[10];
};
I convert the struct into char array and send it to and c# application over a TCP socket and there I convert it back to a c# struct.
[StructLayout(LayoutKind.Sequential)]
public struct Package
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str;
};
The convertion is done properly and I get the message but the problem is when the length of the message is less than the size of the array and I think that it's due to the null terminator in c++ char array.
For instance if the I send "Hello\0" from C++ the char array is something like:
H e l l o \0 \0 \0 \0 \0
And when I get it in c# application it is something like:
H e l l o Ì Ì Ì Ì Ì
And I really don't know what to do with this (personally like to call) junk character 'Ì'.
please help me on this. Any help is appreciated.
Update:
I simply cast the struct to char* and send it over the socket;
Package pkg;
strcpy_s(pkg.str, 'Hello\0');
char* bytes = (char*)&pkg;
send(socket, bytes, sizeof(pkg), NULL);
I don't know any C#, but may be you can solve the problem this way
Package pkg;
strcpy_s(pkg.str, 10, "Hello");
char* bytes = (char*)&pkg;
send(socket, bytes, sizeof(pkg), NULL);
The strcpy_s function takes the size of the dst buffer as an argument to avoid an overflow (see here). I asked in the comments about the way you inovke it, because it doesn't even look like it's valid C++.
The terminating null byte is added to pkg.str automatically and also "Hello" has a terminating null byte after the o character, and you don't have to add it manually.
I assumed that C# knows how to handle the recieved string, so if you send the right string, it should be recived correctly.
You are sending sizeof array instead of strlen of str.
Take notes that if you send with strlen you need to add 1 to send the null termination of string
This is what I usually do in my wrappers dll with serial line
public byte[] RXArray = new byte[length];
byte[] appo = new byte[MsgLength];
Array.ConstrainedCopy(RXArray, NcharsToCopy, appo, 0, MsgLength);
string ConvertedToString = System.Text.Encoding.UTF8.GetString(appo);

Convert a C char * to .Net String then to byte[]

I am having a data conversion issue that need your help.
My project is an InterOp between C and C#, all the data from C is char * type, the data itself could be binary or displayable chars, I.e. each byte is in 0x00 to 0xFF range.
I am using Data marshal::PtrToStringAnsi to convert the char* to String^ in CLI code, but I found some bytes value changed. for example C382 converted to C32C. I guess it is possibly because ANSI is only capable of converting 7-bit char, but 82 is over the range? Can anyone explain why and what is the best way?
Basically what I want to do is, I don't need any encoding conversion, I just want to convert any char * face value to a string, e.g. if char *p = "ABC" I want to String ^s="ABC" as well, if *p="C382"(represents binary value) I also want ^s="C382".
Inside my .NET code, two subclasses will take the input string that either represents binary data or real string, if it is binary it will convert "C382" to byte[]=0xC3 0x82;
When reading back the data, C382 will be fetched from database as binary data, eventually it need be converted to char* "C382".
Does anybody have similar experience how to do these in both directions? I tried many ways, they all seem to be encode ways.
The Marshal class will do this for you.
When converting from char* to byte[] you need to pass the pointer and the buffer length to the managed code. Then you can do this:
byte[] FromNativeArray(IntPtr nativeArray, int len)
{
byte[] retval = new byte[len];
Marshal.Copy(nativeArray, retval, 0, len);
return retval;
}
And in the other direction there's nothing much to do. If you have a byte[] then you can simply pass that to your DLL function that expects to receive a char*.
C++
void ReceiveBuffer(char* arr, int len);
C#
[DllImport(...)]
static extern void ReceiveBuffer(byte[] arr, int len);
....
ReceiveBuffer(arr, arr.Length);

in c# how to convert an var to a char array. char array[8]

in c# how to convert an varto a char array. char[8] array
I can guarantee this var is not too big.
such as, I have
var a = 634711440648369988;
and I want char[8] c store it.
How to do this conversion correctly?
Thanks.
Use BitConverter.GetBytes(long) or BitConverter.GetBytes(ulong)
You can just cast it to a string and use the ToCharArray method.
char [ ] c = a.ToString().ToCharArray();
In C# there is no such thing as char[8]. An array of char would be char[].
I guess you are coming at this from a C++ viewpoint and actually want an array of bytes, of length 8. In which case the type you need is byte[]. Note that you want byte[] rather than char[] since char in C# is a 16 bit data type.
You can obtain what you need by calling BitConverter.GetBytes(). When you call this function passing an 8 byte integer, the returned array will be a byte[] with length equal to 8, as stated in the documentation.
int a = 123412;
char[] d = a.ToString().ToCharArray();
foreach (char c in d)
{
Console.WriteLine(c);
}
Thank you everyone. I seen the question for different type. Therefore, I'm writing different types.
Firstly, I did split the string to string array,
Secondly, I did convert the string array to var array,
Thirdly, I did convert var array to char array.
string input="q;w;e;r;t;y";
string[] roleSplit = new string[input.Length];
roleSplit = input.Split(';');
var varArray = roleSplit.SelectMany(x => x.ToCharArray());
char[] charArray = varArray.ToArray();

Passing a byte array from C# into C++ com object with C++ filling array

I need to pass a byte array into a C++ com object from C#. C++ will then fill the buffer for C# to read.
c++ function definition
STDMETHODIMP CSampleGrabber::GetBuffer(byte* bd)
{
int p=0;
while (p< nBufSize) {
bd[p]=pLocalBuf[p];
p++;
}
c# code :
byte[] byTemp = new byte[nBufSize];
igb.GetBuffer(ref byTemp);
This crashes the program with no exception. Please can someone help. Thanks
SOLVED:
with
byte[] byTemp = new byte[nBufSize];
GCHandle h = GCHandle.Alloc(byTemp, GCHandleType.Pinned);
igb.GetBuffer(h.AddrOfPinnedObject());
Thanks
The parameter should not be declared as ref. You want something like:
uint GetBuffer(byte[] bd);
If you include the ref you are passing a pointer to the array, when you just want the array. (And by array, I mean pointer to the first element.)
I know this is an old question, but Google brought me here so it might bring someone else.
If you're using P/Invoke to call:
... GetBuffer(byte* bd)
it should look something along the lines of
[DllImport("MyDll.dll")]
... GetBuffer(ref byte bd);
And a buffer array in c# should be passed in like this:
var arr = new byte[Length];
GetBuffer(ref arr[0]);
This also works with char*, as you can just pass in the same byte array reference and then use string s = Encoding.<encoding>.GetString(arr);

How to read byte blocks into struct

I have this resource file which I need to process, wich packs a set of files.
First, the resource file lists all the files contained within, plus some other data, such as in this struct:
struct FileEntry{
byte Value1;
char Filename[12];
byte Value2;
byte FileOffset[3];
float whatever;
}
So I would need to read blocks exactly this size.
I am using the Read function from FileStream, but how can I specify the size of the struct?
I used:
int sizeToRead = Marshal.SizeOf(typeof(Header));
and then pass this value to Read, but then I can only read a set of byte[] which I do not know how to convert into the specified values (well I do know how to get the single byte values... but not the rest of them).
Also I need to specify an unsafe context which I don't know whether it's correct or not...
It seems to me that reading byte streams is tougher than I thought in .NET :)
Thanks!
Assuming this is C#, I wouldn't create a struct as a FileEntry type. I would replace char[20] with strings and use a BinaryReader - http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx to read individual fields. You must read the data in the same order as it was written.
Something like:
class FileEntry {
byte Value1;
char[] Filename;
byte Value2;
byte[] FileOffset;
float whatever;
}
using (var reader = new BinaryReader(File.OpenRead("path"))) {
var entry = new FileEntry {
Value1 = reader.ReadByte(),
Filename = reader.ReadChars(12) // would replace this with string
FileOffset = reader.ReadBytes(3),
whatever = reader.ReadFloat()
};
}
If you insist having a struct, you should make your struct immutable and create a constructor with arguments for each of your field.
If you can use unsafe code:
unsafe struct FileEntry{
byte Value1;
fixed char Filename[12];
byte Value2;
fixed byte FileOffset[3];
float whatever;
}
public unsafe FileEntry Get(byte[] src)
{
fixed(byte* pb = &src[0])
{
return *(FileEntry*)pb;
}
}
The fixed keyword embeds the array in the struct. Since it is fixed, this can cause GC issues if you are constantly creating these and never letting them go. Keep in mind that the constant sizes are the n*sizeof(t). So the Filename[12] is allocating 24 bytes (each char is 2 bytes unicode) and FileOffset[3] is allocating 3 bytes. This matters if you're not dealing with unicode data on disk. I would recommend changing it to a byte[] and converting the struct to a usable class where you can convert the string.
If you can't use unsafe, you can do the whole BinaryReader approach:
public unsafe FileEntry Get(Stream src)
{
FileEntry fe = new FileEntry();
var br = new BinaryReader(src);
fe.Value1 = br.ReadByte();
...
}
The unsafe way is nearly instant, far faster, especially when you're converting a lot of structs at once. The question is do you want to use unsafe. My recommendation is only use the unsafe method if you absolutely need the performance boost.
Base on this article, only I have made it generic, this is how to marshal the data directly to the struct. Very useful on longer data types.
public static T RawDataToObject<T>(byte[] rawData) where T : struct
{
var pinnedRawData = GCHandle.Alloc(rawData,
GCHandleType.Pinned);
try
{
// Get the address of the data array
var pinnedRawDataPtr = pinnedRawData.AddrOfPinnedObject();
// overlay the data type on top of the raw data
return (T) Marshal.PtrToStructure(pinnedRawDataPtr, typeof(T));
}
finally
{
// must explicitly release
pinnedRawData.Free();
}
}
Example Usage:
[StructLayout(LayoutKind.Sequential)]
public struct FileEntry
{
public readonly byte Value1;
//you may need to play around with this one
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public readonly string Filename;
public readonly byte Value2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public readonly byte[] FileOffset;
public readonly float whatever;
}
private static void Main(string[] args)
{
byte[] data =;//from file stream or whatever;
//usage
FileEntry entry = RawDataToObject<FileEntry>(data);
}
Wrapping your FileStream with a BinaryReader will give you dedicated Read*() methods for primitive types:
http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx
Out of my head, you could probably mark your struct with [StructLayout(LayoutKind.Sequential)] (to ensure proper representation in memory) and use a pointer in unsafe block to actually fill the struct C-style. Going unsafe is not recommended if you don't really need it (interop, heavy operations like image processing and so on) however.
Not a full answer (it's been covered I think), but a specific note on the filename:
The Char type is probably not a one-byte thing in C#, since .Net characters are unicode, meaning they support character values far beyond 255, so interpreting your filename data as Char[] array will give problems. So the first step is definitely to read that as Byte[12], not Char[12].
A straight conversion from byte array to char array is also not advised, though, since in binary indices like this, filenames that are shorter than the allowed 12 characters will probably be padded with '00' bytes, so a straight conversion will result in a string that's always 12 characters long and might end on these zero-characters.
However, simply trimming these zeroes off is not advised, since reading systems for such data usually simply read up to the first encountered zero, and the data behind that in the array might actually contain garbage if the writing system doesn't bother to specifically clear its buffer with zeroes before putting the string into it. It's something a lot of programs don't bother doing, since they assume the reading system will only interpret the string up to the first zero anyway.
So, assuming this is indeed such a typical zero-terminated (C-style) string, saved in a one-byte-per-character text encoding (like ASCII, DOS-437 or Win-1252), the second step is to cut off the string on the first zero. You can easily do this with Linq's TakeWhile function. Then the third and final step is to convert the resulting byte array to string with whatever that one-byte-per-character text encoding it's written with happens to be:
public String StringFromCStringArray(Byte[] readData, Encoding encoding)
{
return encoding.GetString(readData.TakeWhile(x => x != 0).ToArray());
}
As I said, the encoding will probably be something like pure ASCII, which can be accessed from Encoding.ASCII, standard US DOS encoding, which is Encoding.GetEncoding(437), or Windows-1252, the standard US / western Europe Windows text encoding, which you can retrieve with Encoding.GetEncoding("Windows-1252").

Categories

Resources