php - 你如何将 Rust 中的整数转换为 C 中的 char*

标签 php c rust ffi

我有以下用例。 C 中的结构如下所示:

typedef struct _zend_internal_arg_info {
    const char *name;
    zend_type type;
    zend_uchar pass_by_reference;
    zend_bool is_variadic;
} zend_internal_arg_info;

通常 name 字段包含函数名称。但是由于内部实现,这个字段也可以携带一个整数。在 C 端有一个宏像这样进行转换:

(const char*)(unsigned long int)(1)

我想做的是在 Rust end 上做同样的转换。我最终得到了以下代码:

fn create_null_argument(required_args: u8, return_reference: bool) -> ZendFunctionArgument {
    let required_args_ref = Box::into_raw(Box::new(required_args as i8)) as *const i8;
    ZendFunctionArgument {
        arg: php_bindings::_zend_internal_arg_info {
            name: required_args_ref,
            type_: 0,
            pass_by_reference: if return_reference { 1 } else { 0 },
            is_variadic: 0,
        },
    }
}

这似乎适用于以下测试:

let arguments_ptr = ZendFunctionArguments::new(5, true).into_raw();
unsafe {
    let arguments: Vec<php_bindings::_zend_internal_arg_info> = Vec::from_raw_parts(arguments_ptr as *mut _, 1, 1);
    let required_args = *arguments[0].name;
    assert_eq!(5, required_args);
}

不幸的是,在 PHP 端(当代码被执行时)每次执行时该值都是完全随机的。 我想在这里问的是,与 C 端的转换 ((const char*)(unsigned long int)(1)) 相比,我转换 i8 的方式是否正确?

----编辑-----

更多细节。生成的 PHP 绑定(bind):

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _zend_internal_arg_info {
    pub name: *const ::std::os::raw::c_char,
    pub type_: zend_type,
    pub pass_by_reference: zend_uchar,
    pub is_variadic: zend_bool,
}

这是一个未使用的结构,其中包含对这种扭曲逻辑的一些描述:

/* the following structure repeats the layout of zend_internal_arg_info,
 * but its fields have different meaning. It's used as the first element of
 * arg_info array to define properties of internal functions.
 * It's also used for the return type.
 */
typedef struct _zend_internal_function_info {
    zend_uintptr_t required_num_args;
    zend_type type;
    zend_bool return_reference;
    zend_bool _is_variadic;
} zend_internal_function_info;

这是在 c 中通常使用的整个宏 beig:

#define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args)  \
    static const zend_internal_arg_info name[] = { \
        { (const char*)(zend_uintptr_t)(required_num_args), 0, return_reference, 0 },

zend_uintptr_t 是:

typedef uintptr_t zend_uintptr_t;

然后:

typedef unsigned long int   uintptr_t;

和结构:

pub struct ZendFunctionArgument {
    arg: php_bindings::_zend_internal_arg_info,
}

最佳答案

您的代码将整数转换为指针 - 正如 Stargateur 在评论中所说,正确的方法是更简单地 required_args as *const::std::os::原始::c_char

相反,您使用 Box::new 在堆上分配 required_args,然后使用 into_raw< 将其从内存管理器手中取出 - 提供指向 required_args 值的指针,在您手动清理它之前,它将永远存在。

This seem to work with the following test

因为您通过执行 *arguments[0].name 将指针取消引用到堆中,并且该指针的值确实是 5

Unfortunatelly on PHP end (when the code is executed) the value is totally random on every execution.

这并不奇怪。由于您的代码的最终结果是该字段的值只是一些指向堆的指针,因此每次运行代码时它都会改变。

关于php - 你如何将 Rust 中的整数转换为 C 中的 char*,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56314294/

相关文章:

javascript - 使用 PHP include 获取本地 js kosher?

php - MySQL:选择一个月的数据分为多个时间段

rust - 是否可以在文档本身中显示文档测试的输出?

tcp - 你如何阅读 &mut [0; 的内容? 128]?

rust - 在容器之后创建借用值时,如何添加对容器的引用?

php - 由 Taxonomy Meta 过滤的自定义 $wpdb 帖子

php - 删除父元素,使用 saveHTML 将所有内部子元素保留在 DOMDocument 中

c++ - Linux 内核中的 C func 签名 : include/linux/sched. h

c - openmp 并行中的浮点异常

c - 平方数但保留符号(在 c 中)