c語言實現簡單版的php z_val結構體
學習過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(structz_val)); doubleVal->type = DOUBLE; doubleVal->value.dval = 1.0; // long struct z_val*longVal=malloc(sizeof(structz_val)); longVal->type = LONG; longVal->value.lval = 1; // string struct z_val*strVal=malloc(sizeof(structz_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
可以看到輸出跟預期一樣,我們也實現了一個“弱型別”的變數,是不是很有成就感呢?
實現上,多閱讀原始碼可以多多參考別人的思維方式和編碼習慣,所謂“站在巨人的肩膀上,才能看得更遠”