Explain how exactly internally occurs in the PHP script interpreter (on windows php.exe
), PHP is written in c , 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:
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);