chr () value out of range (0..255)

1

I'm studying this function, but I'm having trouble understanding when we pass a value outside the range (0..255) for this function.

In the official documentation it presents an algorithm to find the correct value, but I could not get the idea and can reproduce.

I have the following example:

echo chr(300);

What results in me: , that has position 44.

But how do I calculate that by passing the value 300 it returns me the correspondent of position 44?

Thank you!

    
asked by anonymous 17.07.2018 / 15:39

1 answer

4

Explain how exactly internally occurs in the PHP script interpreter (on windows php.exe ), PHP is written in , the code is this:

Code:

PHP_FUNCTION(chr)
{
    zend_long c;

    if (ZEND_NUM_ARGS() != 1) {
        WRONG_PARAM_COUNT;
    }

    ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1)
        Z_PARAM_LONG(c)
    ZEND_PARSE_PARAMETERS_END_EX(c = 0);

    c &= 0xff;
    ZVAL_INTERNED_STR(return_value, ZSTR_CHAR(c));
}

The responsible line is this:

c &= 0xff;

This notation 0x that is in front of ff means hexadecimal (base 16), it is calculated as follows:

  • each f is worth 15, then 16 raised to 1 is 16 even
  • getting 15 * 16
  • 16 raised to 0 is 1
  • getting 15 * 1
  • sum both

The calculation:

15 * 16^1 + 15 * 16^0 = 255
(15 * 16) + (15 * 1)  = 255

The final value is 255

  

Important note: with the exception of zero itself, any value raised to zero will result in 1, for example:

     
  • 3 0 = 1
  •   
  • 10 0 = 1
  •   
  • 22 0 = 1
  •   
  • 2018 0 = 1
  •   

Zero can not be determined:

     
  • 0 0 = undefined
  •   
So by convention in programming is considered to be equal to 1 (0 0 = 1), an example in PHP can be so test with the pow(base, expoente) function:

var_dump(pow(16, 0));
var_dump(pow(0, 0));
     

Or in PHP 5.6 +:

var_dump(16 ** 0);
var_dump(0 ** 0);
     

Example link

Just to better explain the base 16 formula, if it were this 0xff00 would look like this:

15 * 16^3 + 15 * 16^2 = 65280

Operation:

(15 * 256) + (15 * 4096) = 65280
3840       + 61440       = 65280

The value 65280

  • then the rightmost value is always raised to zero
  • the second plus right raised to a
  • the third from right to left is raised to two

And so on, as in the second example we had two zeros after ff (which results in zero in the calculation and so I disregarded the formula), then one of them was raised to 2 and the other one raised to three.

Returning the formula, in the result of the program execution (of the function PHP_FUNCTION(chr) ) we will have this:

c &= 255;

The &= operator is equal to this c = c & 255; , this & (or &= ) operator is a bitwise operator called AND ( not to confuse) with && , although similar) to binary logic, then in an operation it will compare bit by bit and will return a 1 whenever both when compared are 1, has a response on the site about this:

Then 255 is equal to 011111111 and the value you put 300 would be equal to 0100101100 , as 255 in bits is smaller then a zero is added to your left (same value if it was unlike 255 & 300 ) :

255:       0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1
300:       0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0
------------------------------------------------
Resultado: 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0

Then we will have 0000101100 converted converted to 44

Note: To make it easier to understand the operations you can remove the leading zeros, like this:

255:       0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1
300:       1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0
---------------------------------------------
Resultado: 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0

The converted value will be the same at the end.

These operations can be done in several programming languages (I do not know if there are any that do not support it), so you can test in JavaScript:

var valor = prompt('Insira o numero');
var range = 255;

valor = parseInt(valor);

if (valor) {
    var x = valor & range;
    alert(x);
} else {
    alert('Numero inválido');
}

An example in PHP would be:

<?php

$valor = 44;
$range = 255;

$x = $valor & $range;

var_dump($x);
    
17.07.2018 / 19:47