嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2016-03-23 2190 次浏览 标签 : CPHP 扩展开发

PHP 扩展开发的文章,我均已更新至《TIPI》(下面的博文可能已经过时,以 TIPI 上的内容为准)。

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

比如PHP5扩展的方法PHP_METHOD和函数PHP_FUNCTION中如下使用zval retval,而不是使用指针声明,则会报错,注释里是编译时的报错信息

zval retval;
MAKE_STD_ZVAL(&retval); // error: lvalue required as left operand of assignment
RETURN_ZVAL(&retval, 1, NULL); // error: lvalue required as unary ‘&’ operand

当声明的时候使用指针,则不会报错了

zval *retval;
MAKE_STD_ZVAL(retval);
RETURN_ZVAL(retval, 1, NULL);

MAKE_STD_ZVAL 的问题

是因为PHP里很多宏都是对函数的简写,所以忘记了宏和函数的区别了。

#include <stdio.h>
#include <stdlib.h>

typedef struct _zval_struct {
	unsigned int refcount__gc;
} zval;

#define MAKE_STD_ZVAL(zv)	(zv) = (zval *) malloc(sizeof(zval));

int main(int argc, char const *argv[])
{
	zval retval;
	MAKE_STD_ZVAL(&retval);
	return 0;
}

也就是说这里等价于

(&retval) = (zval *) malloc(sizeof(zval));

如此当然不对了。

如果是使用函数就应该这样写

#include <stdio.h>
#include <stdlib.h>

typedef struct _zval_struct {
	unsigned int refcount__gc;
} zval;

void make_std_zval(zval *zv);

int main(int argc, char const *argv[])
{
	zval retval;
	make_std_zval(&retval);
	retval.refcount__gc = 1;
	printf("%d\n", retval.refcount__gc);

	return 0;
}

void make_std_zval(zval *zv){
	zv = (zval *) malloc(sizeof(zval));
}

RETURN_ZVAL 的问题

我也把问题抽出来,也是宏和函数的区别问题

#include <stdio.h>
#include <stdlib.h>

#define ZVAL_ZVAL(z, zv, copy, dtor) {			\
		*(z) = *(zv);							\
		if (dtor) {								\
			_zval_ptr_dtor(&zv);				\
	    }										\
	}

#define RETVAL_ZVAL(zv, copy, dtor)		ZVAL_ZVAL(return_value, zv, copy, dtor)

#define RETURN_ZVAL(zv, copy, dtor)		{ RETVAL_ZVAL(zv, copy, dtor); }

typedef struct _zval_struct {
	unsigned int type;
} zval;

void _zval_ptr_dtor(zval **zval_ptr)
{

}

int main(int argc, char const *argv[])
{

	zval *return_value;
	// 正确
    // zval *retval;
    // RETURN_ZVAL(retval, 1, NULL);

    // 错误
    zval retval;
    RETURN_ZVAL(&retval, 1, NULL);

    return 0;
}

在上面的代码中第7行和34行都对retval取了地址符,在34行因为不是函数,就等同于取了两次地址符操作,所以出错了。

同时发现Mac上的GCC和Centos的GCC不一样

#Mac 上的报错信息
zhoumengkangdeiMac:Downloads zhoumengkang$ gcc a.c
a.c:34:5: error: cannot take the address of an rvalue of type 'zval *' (aka 'struct _zval_struct *')
    RETURN_ZVAL(&retval, 1, NULL);
    ^           ~~~~~~~
a.c:13:40: note: expanded from macro 'RETURN_ZVAL'
#define RETURN_ZVAL(zv, copy, dtor)             { RETVAL_ZVAL(zv, copy, dtor); }
                                                  ^
a.c:11:38: note: expanded from macro 'RETVAL_ZVAL'
#define RETVAL_ZVAL(zv, copy, dtor)             ZVAL_ZVAL(return_value, zv, copy, dtor)
                                                ^
a.c:7:19: note: expanded from macro 'ZVAL_ZVAL'
                        _zval_ptr_dtor(&zv);                            \
                                       ^
1 error generated.
#Centos 上的报错信息
[root@localhost unix]# gcc 
a.c
test.c: In function ‘main’:
test.c:35: error: lvalue required as unary ‘&’ operand


嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表