存档

‘php’ 分类的存档

php中的unsigned long类型

2009年7月16日 周翔 没有评论

最近遇到一个问题:
在mysql的表中有一个bigint(20) unsigned 的字段 F_flag.这个bigint相当于一个unsigned long.这个字段的每个二进制位是否为1代表一定意义.简单的说把这个字段当一个64位的bitmap来用.现在需要更新表中一条记录的这个字段.使64,22,1位变位1.

$flag = pow(2, 63)+pow(2, 21)+1;

$sql  = 'update t_table set F_flag ='. $flag. 'where F_id=123';

但是你会发现执行完这条语句后,数据库中的记录并没有更新成你所想要的值.
为什么?
首先我们来看看php中的变量到底是怎么样的:

typedef union _zvalue_value {
        long lval;					/* long value */
        double dval;				/* double value */
        struct {
                char *val;
                int len;
        } str;
        HashTable *ht;				/* hash table value */
        zend_object_value obj;
} zvalue_value;

php中的变量都是一个这样的union数据结构.相当于所有的整形都是用long表示的.而当这个数超出long的范围.它会自动的转换成double去表示.因此前面的$flag已经是一个double了.这样就会存在精度问题.最后导致数据库的更新不正确.
改进后的做法.

$flag = (1 << 63 ) & (1 << 21) & 1;
$flag = sprintf("%u", $flag);
$sql  = 'update t_table set F_flag ='. $flag. 'where F_id=123';

这样就不会出现问题.因为php中的<<不会引起转换,而只是简单的二进制操作.sprintf也只是简单的对c语言中vsprintf的一个简单包装.返回的字符串符合我们的要求.

分类: php 标签: