关于64位PHP仍然使用32位数字的问题

zsx in 记录整理 / 4 / 12376

首先,我们知道有两个常量。PHP_INT_MAXPHP_INT_SIZE

根据PHP官方手册所说,

整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号)。64 位平台下的最大值通常是大约 9E18。PHP 不支持无符号整数。Integer 值的字长可以用常量 PHP_INT_SIZE来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX 来表示。

但是,当我们在Windows下使用64位PHP(版本5.6.4和5.2.17)的时候,PHP_INT_SIZE为4,PHP_INT_MAX为2^31-1。与之相反的是,如果在Linux下使用64位PHP,PHP_INT_SIZE为8,PHP_INT_MAX为2^63-1。PHP Bugs官方也有这么一条BUG报告:https://bugs.php.net/bug.php?id=64863

以下是我的输出

D:\Website\IIS>cat int.php

<?php

echo 'PHP_VERSION = ' . PHP_VERSION . "\n";

echo 'PHP_INT_MAX = ' . PHP_INT_MAX . "\n";

echo 'PHP_INT_SIZE = ' . PHP_INT_SIZE . "\n";

D:\Website\IIS>php int.php

PHP_VERSION = 5.6.4

PHP_INT_MAX = 2147483647

PHP_INT_SIZE = 4



D:\Website\IIS>php --version

PHP 5.6.4 (cli) (built: Dec 17 2014 13:23:31)

Copyright (c) 1997-2014 The PHP Group

Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies

    with Xdebug v2.2.7, Copyright (c) 2002-2015, by Derick Rethans



D:\Website\IIS>

为什么呢?

还是查代码。

我们可以在PHP的main/main.c中查到

在PHP 5.6.4中,代码(https://github.com/php/php-src/blob/PHP-5.6.4/main/main.c#L2233 )为

REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS);

嗯,那看来和C语言的long长度有关。那应该是编译器的问题了。

我们知道,PHP在Windows下用的VC++编译器。那试试看咯。

先上代码

#include <iostream>

#include <climits>

using namespace std;



int main() {

	cout << "int (size = " << sizeof(int) << ") max = " << INT_MAX << endl;

	cout << "long (size = " << sizeof(long) << ") max = " << LONG_MAX << endl;

	cout << "llong (size = " << sizeof(long long) << ") max = " << LLONG_MAX << endl;

	return 0;

}

首先是在x86下编译的结果

Z:\>cl /EHsc int.cpp && int

Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x86

Copyright (C) Microsoft Corporation.  All rights reserved.



int.cpp

Microsoft (R) Incremental Linker Version 11.00.60610.1

Copyright (C) Microsoft Corporation.  All rights reserved.



/out:int.exe

int.obj

int (size = 4) max = 2147483647

long (size = 4) max = 2147483647

llong (size = 8) max = 9223372036854775807



Z:\>

再用64位编译器编译吧。

Z:\>cl /EHsc int.cpp && int

Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x64

Copyright (C) Microsoft Corporation.  All rights reserved.



int.cpp

Microsoft (R) Incremental Linker Version 11.00.60610.1

Copyright (C) Microsoft Corporation.  All rights reserved.



/out:int.exe

int.obj

int (size = 4) max = 2147483647

long (size = 4) max = 2147483647

llong (size = 8) max = 9223372036854775807

嗯,很好,我们用g++编译器编译呢?

$ g++ -v

Using built-in specs.

COLLECT_GCC=g++

COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/lto-wrapper.exe

Target: x86_64-pc-cygwin

Configured with: /cygdrive/i/szsz/tmpp/cygwin64/gcc/gcc-4.8.3-2/src/gcc-4.8.3/configure --srcdir=/cygdrive/i/szsz/tmpp/c

ygwin64/gcc/gcc-4.8.3-2/src/gcc-4.8.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdi

r=/usr/libexec --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib --datarootdir=/usr/share --

docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target

=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --enable-shared --enable-shared-libgcc --enable-sta

tic --enable-version-specific-runtime-libs --enable-bootstrap --disable-__cxa_atexit --with-dwarf2 --with-tune=generic -

-enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enabl

e-libgomp --disable-libitm --enable-libquadmath --enable-libquadmath-support --enable-libssp --enable-libada --enable-li

bgcj-sublibs --disable-java-awt --disable-symvers --with-ecj-jar=/usr/share/java/ecj.jar --with-gnu-ld --with-gnu-as --w

ith-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --libexec

dir=/usr/lib

Thread model: posix

gcc version 4.8.3 (GCC)



sx@zsx-pc /cygdrive/z

$ g++ int.cpp -o int & ./int

[1] 25508

int (size = 4) max = 2147483647

long (size = 8) max = 9223372036854775807

llong (size = 8) max = 9223372036854775807

比较一下这两个编译器long的size和max,就能知道为什么在老版本PHP中INT_MAX的值不一样了。

然而,在PHP7中,这里又有了些修改。(https://github.com/php/php-src/blob/master/main/main.c#L2176)

REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", SIZEOF_ZEND_LONG, CONST_PERSISTENT | CONST_CS);

而SIZEOF_ZEND_LONG的定义,在这里(https://github.com/php/php-src/blob/master/Zend/zend_long.h  )

所以,PHP7中,应该不会再出现这个问题了。

如果本文对你有帮助,你可以用支付宝支持一下:

Alipay QrCode
c at 2015/3/13[回复]
抱歉占个地,关于Zblog有个问题想请教下。
我看到ZB的数据库中浏览zbp_tag标签表只记录了标签所含文章数量,而zbp_post表中log_Tag字段记录了所含标签。
那按标签查看的时候,是检索所有文章所含的log_Tag字段,返回包含此标签的文章?如果那样的话如果文章和标签都很多的时候,感觉负载会很大……?
还是说有别的方法减轻负载,比如缓存或者索引一类?不太熟悉ZB架构,望指教!
zsx at 2015/3/21[回复]
建议下次还是到Z-Blog论坛提问好了……这里就是LIKE,没有任何优化。优化开启大数据插件后才存在。
c at 2015/3/22[回复]
感谢~