ID:1873258
 
(See the best response by Lummox JR.)
Hey, I am working on a extra cool project (that I'll publish has a library for Byond users) that works with Binary code. I really enjoy working on this topic, I mean Binary is a super interesting thing...

The project is almost complete but i can't convert my strings to integer they way I want to.

For exemple, Imagine this situation:

1st. A function returns this string "01010100 01100101 01110011 01110100" .

2nd. I need to pass that string as an integer argument for a proc(it must be integer !! ). This is the proc proc/BinaryHandler(n as num)

3rd. So I call the proc BinaryHandler(text2num(returned_string)) but this text2num(returned_string) will be converted into scientific notation... I can't work with scientific notation... Binary and scientific notation don't go well together.

Is there any way around? Is there any way to disable scientific notation? I am aware that BYOND uses single-precision floating point for its numbers, and only supports bit-wise operations for the first 16 bits but I really need to find an alternative way.... What do you think?

As always thanks for your help,
Hug,
,Misty,
You can't store integers in a float without losing precision. You can display numbers without the scientific notation by using num2text and specifying the precision, but you'll note that the number will likely not match the number that you put in.

I think you're out of luck if you're trying to keep precision and use the numbers in DM.
If you use num2text(), you can provide a number of significant digits to show.
Use text2ascii(). Keep it as a string and just subtract the decimal value of 0 from the result. That'll give you 0 or 1, which you can then multiply by 2^(pos-1) and add to a final number.
Humm I really appreciate your answers but none of them is what I am looking for.

But I've got an idea... I think it might actually work...

Remember this binary code that I showed you? 01010100 01100101 01110011 01110100 well I have to use it as an argument for a c# function (via dll). This has to be done! The dll function must be used!

Byond only works with dlls via integer and char const** arguments. char const** is typical from C++ and not C# so that's not an option (well, I could manage c# to use that type of arguments but it would require a lot of work). This leaves me with the integer option.

So this is my idea:

1st. Imagine I have this Binary code 01100101
2nd. I can't use that as an integer argument since it will be transformed into scientific notation so I'll separate each number. For example this number 123 will be split in 1, 2 and 3 and each splited number will be stored inside a list. I'll achieve this by using this proc:

var/list/Splited = list()
proc/Split(t as text)
EmptyList(Splited)
if(length(t)>1)
for(var/i = 2, i<=length(t) +1, i++)
Splited.Add(text2num( copytext(t,i-1,i) ))

else
Splited.Add(text2num(t))


3rd. Now I have my whole binary code splited and stored inside a list.

4th. I'll now call this proc that will use each splited number as an argument for my c# function. This function will store each splited number inside a c# List (i'll explain why later)

This is my proc:
proc/Send_2_DLL(L, /var/list) // I'll use the Splited list as an argument for this proc
for(var/each in L)
world<<call("MysqlConnector","StoreCode")(each)


This is my C# function that is being called in the proc above:
        public static List<int> SplitedCode = new List<int>();
public static String StoreCode(int splitedNum) {
try
{
SplitedCode.Add(splitedNum);
return "Success";
}
catch (Exception ex)
{
return ex.ToString();
}

}


5th. Now All I have to do is join the numbers that are in the c# list in order to get my whole binary code again
01100101


6th. I call this c# function in byond:
        public static String JoinAll() {

try
{
string MyBinary = string.Empty;
foreach (int item in SplitedCode)
{
MyBinary = MyBinary + item.ToString();

}
return MyBinary; // Just to check if this works
}
catch (Exception ex)
{

return ex.ToString(); //If there is any problem
}

}


7th. Now that I finally have rebuilt my binary in my dll i'll use it as a string argument for some c# functions. (Like I said before, I couldn't just send my binary as string from Byond to my dll since Byond only passes integers and char const** and char const** isn't accepted well in c#).


The Problem is that Byond isn't passing integers correctly to c#:

for example, if I call this on Byond:

proc/SendInt(n as num)
world<<call("MysqlConnector","GetInt")(n)

My number will be used as an argument in this c# function:

public static String GetInt(int n) { return n.ToString(); }


The problem is that this function isn't outputting the correct number. Byond won't output the number that I wrote.





I'm so sorry for bothering you with this.
As always thanks for your patience and kindness.

Strong Hug for you all
That's because BYOND only passes char* to the DLL, not ints. The integer argument that it sends is just the number strings passed in the array of string arrays.

Convert numbers to strings before passing them to a DLL.

EDIT: It seems that you are having trouble passing the strings to the DLL? Have you taken a look at this post yet? They use strings to pass information.
I have read and re-read it but i still don't understand very well how to pass strings to my DLL. I tried to pass the strings as integer (because the string only has "numbers" in it) to my dll and then make it a string again like I showed in my previous post but with no success (but thanks to you I understand why it wasn't working ).

In the post that you told me to read he uses something like this to pass strings but I don't understand it very well
String[] Args = new String[NumArgs];
IntPtr[] ArgPtrs = new IntPtr[NumArgs];
Marshal.Copy(ArgPtr, ArgPtrs, 0, NumArgs);
for(int X = 0; X < NumArgs; X++)
Args[X] = Marshal.PtrToStringAnsi(ArgPtrs[X]);
Can you explain to me what it does? and break it line by line?

I feel I am asking too much from you but I really need to figure this out. Ty
As a forewarning, I use C++ for my DLLs, so this isn't exactly my strong suit.

First of all, you need to set up UnmanagedExports. This allows you to export your functions. I believe that you have already done this.

Second, that snippet is best when looked at with context. Let's rewrite it to look like this:
class Class1 {
[DllExport("merge", CallingConvention = CallingConvention.Cdecl)] // Name our exported function, and the Calling Convention is technical stuff.
[return: MarshalAs(UnmanagedType.LPStr)] // Ensure we return a string formatted so BYOND can use it
public static String Merge(int NumArgs, IntPtr ArgPtr) { // BYOND passes us two params, int and char**, so use these.
String[] Args = new String[NumArgs];
IntPtr[] ArgPtrs = new IntPtr[NumArgs];
Marshal.Copy(ArgPtr, ArgPtrs, 0, NumArgs);
for(int X = 0; X < NumArgs; X++){
Args[X] = Marshal.PtrToStringAnsi(ArgPtrs[X]);
}
}
}

The first thing that you'll notice is that we use an IntPtr rather than a char**. The reason that we can do this is because a pointer is a pointer, and we can treat it as the type of pointer that we want.

Next,
String[] Args = new String[NumArgs];

This just declares an array of strings where we will store all of the arguments passed.


IntPtr[] ArgPtrs = new IntPtr[NumArgs];

Remember that the original IntPtr that we had is basically a char**. So that means that it is pointing to an array of pointers. We create this array to store those pointers in.


Marshal.Copy(ArgPtr, ArgPtrs, 0, NumArgs);

This copies all of the pointers from the argument into the array declared above.


for(int X = 0; X < NumArgs; X++)
Args[X] = Marshal.PtrToStringAnsi(ArgPtrs[X]);

Finally, we go through each pointer and get its string, storing it in the first array that we declared. Now, you can access each argument by getting the corresponding element from Args.
Wait, if you convert a binary string to an integer using text2num, you're not actually converting it to base-10.
Mightymo, Thank you so much for explaining that to me so carefuly :) Now I understand what that does and how it should be used. Now I can fix my code!! :D

Kai, I'm not converting the whole binary string. Like I said, I am converting each number of the binary string individualy (making use of the copytext proc). And even if I wanted to convert the numbers to base-10 I just have to pass the whole binary string as a const char** argument (like Mightymo taught me) in a c# function that will convert the string in a base 10 number Convert.ToInt32(MyStringBinary,10). But I don't need to convert it to base10 at all. I can work with it as a string (passing the strings as const char** arguments). No need to complicate things. But thanks for alerting me :D
proc
binary2num(string)
var/len = length(string)
var/pos = 0
var/exp = 1
. = 0
while(++pos<=len)
. += (text2ascii(string,pos)-48) * exp
exp *= 2


Seems like you are over-engineering.
In response to Ter13
Best response
Er, wouldn't that interpret the string backwards, since the first bit becomes the LSB? I think you want something like this:

proc
binary2num(string)
var/len = length(string)
var/pos = 0
. = 0
while(++pos<=len)
. += (text2ascii(string,pos)-48)
. *= 2

Bonus: only one multiplication in the loop.
Spot on, Lummox. Thanks for the correction.