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