c语言实现简单版的php z_val结构体
2019年2月26日 · 227 字 · 2 分钟
源码
学习过PHP的人都知道PHP是基于C语言开发的,但是C语言是强类型的,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;
zend_ast *ast;
} zvalue_value;
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uint refcount__gc;
zend_uchar type; /* active type */
zend_uchar is_ref__gc;
};
type保存了实际的类型,而value这个共用体保存了具体的值,我们使用到变量的时候需要根据变量类型来取出**_zvalue_value中保存的具体值。 采用union能够避免内存浪费,同一时刻,一个_zval_struct中的共用体zvalue_value**只有一个成员会分配内存,避免了无谓的内存分配。
编码
阅读源码之前,可能觉得是一个很复杂的实现,阅读源码之后,其实也能自己实现,关键是type和value的组合。源码如下:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
enum z_val_type
{
DOUBLE,
LONG,
STRING
};
struct z_val
{
union {
double dval;
long lval;
struct
{
char *val;
int len;
} str;
} value;
enum z_val_type type;
};
void z_val_print(struct z_val *);
int main(void)
{
// double
struct z_val *doubleVal = malloc(sizeof(struct z_val));
doubleVal->type = DOUBLE;
doubleVal->value.dval = 1.0;
// long
struct z_val *longVal = malloc(sizeof(struct z_val));
longVal->type = LONG;
longVal->value.lval = 1;
// string
struct z_val *strVal = malloc(sizeof(struct z_val));
strVal->type = STRING;
strVal->value.str.val = "Hello World!";
strVal->value.str.len = strlen(strVal->value.str.val);
z_val_print(doubleVal);
z_val_print(longVal);
z_val_print(strVal);
free(strVal);
free(longVal);
free(doubleVal);
return 0;
}
void z_val_print(struct z_val *val)
{
switch (val->type)
{
case LONG:
printf("type: long, val: %ld\n", val->value.lval);
break;
case DOUBLE:
printf("type: double, val: %f\n", val->value.dval);
break;
case STRING:
printf("type: string, val: %s, len: %d\n", val->value.str.val, val->value.str.len);
break;
}
}
编译
采用gcc编译
gcc -o union union.c
执行
./union
输出
type: double, val: 1.000000
type: long, val: 1
type: string, val: Hello World!, len: 12
可以看到输出跟预期一样,我们也实现了一个“弱类型”的变量,是不是很有成就感呢? 实现上,多阅读源码可以多多参考别人的思维方式和编码习惯,所谓“站在巨人的肩膀上,才能看得更远”