您的位置:首页 > 编程语言 > PHP开发

使用C开发PHP扩展全过程及相关细节…

2017-06-12 17:10 363 查看
之前一篇介绍了PHP扩展环境搭建及大致项目结构流程介绍

这章将围绕PHP以及C语言变量进行介绍

C语言字符串指针及操作函数

这里主要介绍字符串操作相关,可能大家会很奇怪,为什么我介绍的都是关于变量和字符串的操作知识。事实上我们的网页服务器大部分时间都是在拼接字符串,所以我们用c扩展的时候大部分时间都是在针对内存空间内的字符串进行操作,而php扩展和php交互的时候是通过变量进行传递所以字符串操作和转换是这个里面的基本操作……

以下指针数据类型都是char类型,不同类型的指针移动指针时会移动不同长度。

实际看几个例子

char长度为一字节,16进制为
0xFF     
2进制为1111 1111

int为两个字节    
16进制为 0xFFFF,  2进制为1111 1111 1111 1111

注意:如果在声明类型未指定 unsigned时,那么以上两个类型的 2进制第一位将作为正负值判断而不作为表示数值
1代表负数,0为正数。

注意:上文提到的int并不一定是两个字节,这个长度取决于系统,在32位系统和64位系统中实际表示长度不同。所以,对这类不同系统有变长的变量用其他指针读取的时候务必用sizeof算一下他的长度。

char teststring[50];

声明一个teststring字符串,最大长度50,这个方式在程序执行完毕后会自动释放,这个方式很环保……我目前最喜欢的方式,当然这个方式会浪费一定内存空间……并且不灵活(定长)……不过好在目前这个需求是够用的……

char *ptest;

声明一个字符串指针,注意目前他指向地址未知,我们程序在指定有效空间之前不要对他进行操作,否则肯定会会导致程序崩溃,系统不稳定。

下面两步就是给指针指向一个合法分配的内存空间。

ptest=teststring;

让指针指向teststring的存储空间,这里指针变量实际存储的是这个char串的首个char的内存地址,对与c来说一个字符串在内存中是一个连续的内存空间,在读取使用字符串的时候碰到'\0'时代表这个字符串结束,如果某字符串超过分配空间大小……等着系统挂掉吧……c是不会检测溢出这类事情的……

ptest=malloc(sizeof(char)*50);

此为在运行期间动态分配一块长度为char类型长度*50的空间,这里务必注意在使用完毕后程序结束之前必须释放,否则会导致这块内存在系统重启前不能被其他程序使用,如果调用频繁会导致系统没有可用内存……。

ptest 当前指针地址

*(ptest+1)
相当于teststring[1],即指向第二个字符;

(*ptest)++
相当于teststring[0]++,即指向的第一个字符变量内值+1;

ptest++
相当于teststring[1],这里不同的是以后代码使用ptest时他指向的地址将不是第一个字符,而是第二个,再次提示不同数据类型步进字节个数不同。

关于字符串结尾注意事项

malloc后以及teststring声明后,我们在上面操作中并没有给他赋任何数值,所以他们目前的内容是随机的,务必在对他们进行赋值后再做其他读
取操作,至少要赋值'\0'在首个char内,否则很可能会导致输出50个char内存空间内数据后还会继续输出后面的内存空间内数据直到碰到'\0'。
如果没有进行任何初始化动作直接进行操作的结果会很悲剧。

C一些变量操作函数,这里只是简单罗列一下具体细节自己查看下
strcat(dst,src);                   
字符串拼接,将src追加在dst字符串结尾
sprintf(dst,"%ld",idx)             
将int转换成显示的char,如123转换成"123"保存到dst内
sscanf("123456 ", "%s",
dst);      
将string转换成int,保存到dst内
memset(dst,'\0',100);              
将dst内存区域长度100全部填入\0
strncpy(dst, src,
len);            
将src,拷贝到dst,拷贝长度len,这个不会在结尾打\0要注意

php扩展的一些函数
zend_parse_parameters(ZEND_NUM_ARGS()
TSRMLS_CC, "s", &str1,
&strlen);用于接收函数后参数

注意这里的s代表传入数据为字符串,后面str1为接收字符串变量,strlen为字符串长度,目前已知字符串长度超过4k会被自动截断。其他类型及相关方法,可以参考网上资料……

注意:记得在变量之间来回拷贝追加的时候记得自己判断下追加长度是否超过目前(最大空间长度-1,减1是给结尾\0用),否则会溢出……哎各种溢出。另外,注意一下这几个函数输入输出的数据类型……

PHP变量在C语言的操作
PHP内的脚本经过Zend引擎“翻译”后,变成OPCODE,Zend根据OPCODE做调用以下c方法完成变量的操作

由于内容很多,这里不一一叙述,只是列出一个网上找到的PHP数组操作与C数组操作对应函数操作对比

PHP语法     
     
C语法(arr是zval*)
         
意义


$arr = array();
   
array_init(arr);
              
初始化一个新数组

$arr[] = NULL;
    
add_next_index_null(arr);   
   向数字索引的数组增加指定类型的值

$arr[] = 42;
      
add_next_index_long(arr, 42);

$arr[] = true;
    
add_next_index_bool(arr, 1);

$arr[] = 3.14;
    
add_next_index_double(arr, 3.14);

$arr[] = 'foo';
   
add_next_index_string(arr, "foo", 1);

$arr[] = $myvar;   
add_next_index_zval(arr, myvar);

$arr[0] = NULL;
   
add_index_null(arr, 0);
       
向数组中指定的数字索引增加指定类型的值

$arr[1] = 42;
     
add_index_long(arr, 1, 42);

$arr[2] = true;
   
add_index_bool(arr, 2, 1);

$arr[3] = 3.14;
   
add_index_double(arr, 3, 3.14);

$arr[4] = 'foo';   
add_index_string(arr, 4, "foo", 1);

$arr[5] = $myvar;
    
add_index_zval(arr, 5, myvar);

$arr['abc'] =
NULL;   
add_assoc_null(arr, "abc");
   
向关联索引的数组增加指定类型的值

$arr['def'] =
711;    
add_assoc_long(arr, "def", 711);

$arr['ghi'] = true;   
add_assoc_bool(arr, "ghi", 1);

$arr['jkl'] = 1.44;   
add_assoc_double(arr, "jkl", 1.44);

$arr['mno'] = 'baz';   add_assoc_string(arr,
"mno", "baz", 1);

$arr['pqr'] = $myvar;  add_assoc_zval(arr, "pqr",
myvar);

c指针包装的字符串在回传给PHP的时候建议用estrdup处理下,要不回去获取的可能是未知数据。

PHP的数组在C内读取

主要有两个方式我就介绍我目前使用的方式

看代码:
// input paramter

zval *zval_cookie;//用zval接收php传给php扩展内函数的参数

// running var

HashTable
*hash_cookie;                        
//使用哈希表在c内保存传入数组

HashPosition
hash_pointer;                     
//当前哈希表指针变量

int
hash_count;                                
//哈希表内数据个数

//temp var

char
*key;                  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: