You must be logged in to reply.

Page 1 of 3 out of 25 messages.

Char concat

1 like
Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Hi!

I have a bug with G120, latest firmware.

var s = "11";
s += ' '; // space
// now s = "1132"


So, space char is converted to byte while concatenating.
Reply #1 — Posted 3yr ago
by Gus_ghielectroncs | Employee
Reply #1 — Posted 3yr ago
by Gus_ghielectroncs | Employee
Try in the emulator please.
Reply #2 — Posted 3yr ago
by Mr. John Smith | Legend | 42,263 exp
Reply #2 — Posted 3yr ago
by Mr. John Smith | Legend | 42,263 exp
that's interesting. string += char. = string "1132".

I don't get this bug on my CerbBee or in the emulator.
Reply #3 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Reply #3 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Absolutely! I ported my project from Cerb to G120 and got that bug. Reproduced only on G120.
Reply #4 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Reply #4 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
The code in the first post is simplified. The actual code is located here:

https://github.com/toxsedyshev/imBMW/commit/3dbf075e5fa00f212fe615bad1aa6b26506d807b#diff-65b41d023f3080e0520002788879b121L117

public static String ToHex(this byte[] data, Char spacer)
        {
            String s = "";
            foreach (byte b in data)
            {
                if (s.Length > 0)
                {
                    s += spacer;
                }
                s += b.ToHex();
            }
            return s;
        }
1 like
Reply #5 — Posted 3yr ago (modified)
by mcalsyn | Legend | 48,189 exp
Reply #5 — Posted 3yr ago (modified)
by mcalsyn | Legend | 48,189 exp
I ran the following code based on the code in your source repo:

using System;
using Microsoft.SPOT;

namespace hextest
{
    public class Program
    {
        public static void Main()
        {
            byte[] foo = new byte[] { 0x11, 0x22, 0x33, 0x44 };
            Debug.Print(foo.ToHex(' '));
        }
    }

    public static class Extensions
    {
        const string hexChars = "0123456789ABCDEF";

        public static String ToHex(this byte b)
        {
            return hexChars[b >> 4].ToString() + hexChars[b & 0x0F].ToString();
        }

        public static String ToHex(this byte[] data, Char spacer)
        {
            String s = "";
            foreach (byte b in data)
            {
                if (s.Length > 0)
                {
                    s += spacer;
                }
                s += b.ToHex();
            }
            return s;
        }
    }
}


And I get the same error that you get. However, if I change
s += spacer;

to
s += spacer.ToString();


then it works correctly. I debugged through it with the framework source code and 'spacer' is being implicitly typed as Int32 and then coerced to string via Int32.ToString(). By using .ToString(), this runs an explicit conversion to string first, which avoids the default conversion to Int32. This seems to be an issue in the compiler with the type presumptions and the IL that it is generating, and not in the framework. I get the same results in the emulator, and the framework code seems right - it's just making odd choices as to which framework code to call.

Overall, the code you provided will cause a lot of heap churn through repetitive re-allocation of non-mutable strings and it should be re-written to use StringBuilder. That will run faster and result in less heap fragmentation.
3 likes
Reply #6 — Posted 3yr ago (modified)
by mcalsyn | Legend | 48,189 exp
Reply #6 — Posted 3yr ago (modified)
by mcalsyn | Legend | 48,189 exp
Interesting - VS2013 returns the expected result. VS2015 returns the counter-intuitive result. So it is not related to the framework version. It is a change in the compiler. This is something everybody here should be aware of as it changes some pretty fundamental type-system behavior.

These two VS versions are running different compilers, so it seems that the new (Roslyn) compiler is making different type-coercion choices, and in this case, this seems like a big breaking change, and not necessarily a good one. Seems like a bug to me. I haven't explored whether it is limited to generation of NETMF IL or all IL targets.

EDIT: Win32 C# works as expected under VS2013 and VS2015. This type-coercion weirdness seems to only affect NETMF.
EDIT2 : Filed as issue https://github.com/NETMF/netmf-interpreter/issues/327
Reply #7 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
Reply #7 — Posted 3yr ago
by toxsedyshev | Senior | 1,016 exp
@mcalsyn - Good job, thank you!

About, StringBuilder, yes, I know, thank you! Smiley There are many not optimized methods to avoid "braking" some code in different NETMF versions starting from 4.1. I hope, I'll optimize them later when run out of resources of Cerb.
Reply #8 — Posted 3yr ago
by John_ghielectroncs | Employee
Reply #8 — Posted 3yr ago
by John_ghielectroncs | Employee
@toxsedyshev - When you last tested it on the Cerberus, was it in VS2013 or VS2015? I tested the G30, G80, G120, G400, and Cerberus. All five worked fine in VS2013 while all five failed with your bug in VS2015.

Interestingly, it was only the code @mcalsyn posted that failed. If I ran the below code, VS2013 and VS2015 both gave the expected result.

public class Program {
	public static void Main() {
		var s = "11";
		s += ' ';
	}
}
Reply #9 — Posted 3yr ago
by mcalsyn | Legend | 48,189 exp
Reply #9 — Posted 3yr ago
by mcalsyn | Legend | 48,189 exp
@John - Char constants appear to be getting treated differently than char-typed vars then, because that's the main difference in your snippet.

Page 1 of 3 out of 25 messages.

You must be logged in to reply.