Hi, I have been trying to perfect a method of converting an integer valued 0-65535 into 2 bytes of ascii, and vice versa. I produced a couple of functions which rely on the ord and char functions to do the conversions, but I am noticing extremely unusual bugs.

//-----makeUshort
//str makeUshort(int ushort);
//
function makeUshort($intIn){


//echo "intIn is $intIn\n";


  //if it out of range
  if($intIn > 65535 or $intIn < 0)
    //return false
    return false;
  //get the input as binary
  $asBin = decbin($intIn);


echo "asBin is $asBin\n";


  $byteOne = bindec(substr($asBin,0,8));


echo "byteOne is $byteOne\n";


  $byteTwo = bindec(substr($asBin,8));


echo "byteTwo is $byteTwo\n";


  //get the characters and concatenate them
  $strOut = sprintf("%c%c",$byteOne,$byteTwo);


echo "strOut is '$strOut'\n";


  //return the 2 byte string
  return $strOut;
}

//-----getUshort
//int getUshort(str ushort);
//
function getUshort($strIn){


echo "strIn is '$strIn'\n";


  $msB = ord($strIn{1}); //msB most significant Byte (byte 2)


echo "msB is '$msB'\n";


  $lsB = ord($strIn); //lsB list significant Byte (byte 1)


echo "lsB is '$lsB'\n";


  $intOut = $msB * 256 + $lsB;


echo "intOut is '$intOut'\n";

  return $intOut;
}

The outputs are unusual, for values below 1024 the result was correct in a previous version (seems almost random now). 1024 and above have odd results that I can't understand. I initially thought about the byte order, so I made it multiply the first character by 256 instead, in getUshort (knowing that the way they are formed shouldn't make that correct). This just made it all incorrect. In makeUshort I tried using sprintf to pad the output of dec2bin to add initial 0s so that it was 16 digits long - and then using char twice. But the results were the same as using sprintf to convert into ascii - as I am doing now. I can't figure out the problem in my functions and have about 10 test versions of each messing up the working directory. Can anyone see an alternate solution, or problems in my code that might be causing the bug/s?

I was using this php to test it, (expecting the output to be the same as the input)

<?php
echo getushort(makeUshort(52)) ."\n". getushort(makeUshort(33169)) ."\n\n";
echo getushort(makeUshort(1023)) ."\n". getushort(makeUshort(1024));
?>

and got (without debug from inside the functions):
52
37249

1023
128

    For makeUshort(), instead of trying to go through binary representation, use mathematics. ($intIn &#37; 256) will give you the ordinal value of one char, then (int)($intIn / 256) will give you the ordinal value of the other char.

      Thanks, that works much better than my way.

      function makeUshort($intIn){
        $byte1 = chr($intIn % 256);
        $byte2 = chr($intIn / 256);
        return $byte1 . $byte2;
      }
      

      Almost posted for more help when I tested a number that happened to make a backspace character and confused my results. But I am happy with my new function.

        FYI, I can see two problems in particular with the original code that happen to combine to sometimes produce the correct results.

        First, you swap MSB and LSB over ($byteOne is the MSB, $byteTwo is the LSB, but byte 2 of $str is the MSB, and byte 1 is the LS😎, which is why you get 37249 = 256145+129 instead of 33169 = 256129+145.

        The other hazard is that you take the first eight characters of the binary representation as the MSB, even if that leaves fewer than eight characters for the LSB. decbin(1024) has eleven characters, but instead of [font=monospace][hhh][llllllll][/font] you take [font=monospace][hhhlllll][lll][/font].

        52 => 110100, so the MSB is the first eight characters of that ("110100"oops, or 52 in decimal) , and the LSB the rest ("", or 0). But when putting it back together it's not MSB256+LSB, it's LSB256+MSB = 0*256+52 = 52.

          Well i think i had exhausted the byte orders solutions, though i was sure my initial functions had them correct (I might have posted messed up versions in my opening post). I'm not sure but did you notice i had padded the binary representation to include leading 0s? so the 2 different binary values were just concatenated together, always 8 characters each. But either way, I have solved it now - laserlight's solution was much better than my original method.

            Bozebo wrote:

            I'm not sure but did you notice i had padded the binary representation to include leading 0s?

            I guess you posted messed-up versions in your opening post, 'cos there's no padding there 🙂

            laserlight's solution was much better than my original method.

            No disagreement from me (although if I'd written them I'd probably have used & and >> instead of &#37; and / - seeing as I would have been thinking about bitflipping at the time). Just for a giggle, notice that the "%256" is optional (though I wouldn't rely on that!).

              Weedpacket;10884347 wrote:

              I guess you posted messed-up versions in your opening post, 'cos there's no padding there 🙂
              No disagreement from me (although if I'd written them I'd probably have used & and >> instead of % and / - seeing as I would have been thinking about bitflipping at the time). Just for a giggle, notice that the "%256" is optional (though I wouldn't rely on that!).

              Ah yes, I did post one of my attempted solutions - instead of my original, thought out function. I originally used sprintf on the decbin result, from the whole input integer - then cut it in half and returned both to decimal and found the corresponding characters.

                Write a Reply...