PHP_INT_MIN and -9223372036854775808

Is the output the same? If not, why?

var_dump(PHP_INT_MIN);
var_dump(-9223372036854775808);

I think this kind of question is not suitable as a PHP interview question. But as an interesting point of knowledge, let me talk about this little problem today.

We know that the table value range of 64-bit integers is -9223372036854775808 to 9223372036854775807.

On 64-bit systems, PHP uses signed 64-bit integers to represent IS_LONG. There are two constants to represent these two values, PHP_INT_MIN and PHP_INT_MAX.

On a 64-bit platform, PHP_INT_MIN is equal to -9223372036854775808. What does the question mean? Let’s take a look at the output:

int(9223372036854775807)
float(-9.2233720368548E+18)

The output is really different, so what caused this difference?

When the PHP compiler processes the input of the input file, its processing method for negative numbers is as follows:

-{LNUM}
   => '-' expr { $$ = zend_ast_create(ZEND_AST_UNARY_MINUS, $2); }
   => UNARY_MINUS: 0 - expr

That is, first accept the number after the minus sign as an integer, and then negate it.

So this caused this problem. At the beginning, we said that the maximum positive table value of 64-bit is 9223372036854775807. When PHP is processing -9223372036854775808, 9223372036854775808 exceeds the maximum positive table value range of 64-bit shaping. PHP cannot use one. The symbol 64-bit integer stores it, so it can only be automatically converted to the DOUBLE type. So next…

In fact, in C language, if you write the following code:

int main() {
    long a = -9223372036854775808;
 
    return 0;
}

You should receive a warning similar to the following:

warning: integer constant is so large that it is unsigned

In other words, if you directly write 9223372036854775808, the C compiler will prompt you that this number is too large and should be represented by unsigned. By default, it will be converted to unsigned long for you, and then negative.

Of course, you can also force direct assignment by specifying UL to avoid this warning, but more often, in order to show that there is a pit, everyone usually writes this way (for example, in ubuntu’s /usr/include/stdint.h ):

#define INT64_MIN  (-__INT64_C(9223372036854775807)-1)

That is to use an expression instead of directly writing a literal. Correspondingly, we can also write this in the script:

$min = -9223372036854775807 - 1;

To avoid this restriction, PHP_INT_MIN can be expressed normally. In fact, when PHP_INT_MIN was not defined before PHP7, we were also used to writing, such as some test scripts in the PHP source code (ext/date/tests/date_create-relative.phpt):

if (!defined('PHP_INT_MIN')) {
    define('PHP_INT_MIN', intval(-PHP_INT_MAX - 1));
}