简体   繁体   English

如何在Rust中将整数转换为C中的char *

[英]How do you cast integer in Rust to char* in C

I have the following use case. 我有以下用例。 A struct in C looks like this: 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;

Normally the name field contains a function name. 通常, name字段包含函数名称。 But due to internal implementation this field can also carry an integer. 但是由于内部实现,该字段也可以携带整数。 On C end there is a macro doing the casting like this: 在C端,有一个宏在进行这样的转换:

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

What I want to do is to do the same cast on Rust end. 我想要做的是在Rust端执行相同的转换。 I ended up with the following code: 我最终得到了以下代码:

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,
        },
    }
}

This seem to work with the following test: 这似乎适用于以下测试:

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);
}

Unfortunatelly on PHP end (when the code is executed) the value is totally random on every execution. 不幸的是,在PHP端(执行代码时),该值在每次执行时都是完全随机的。 What I want to ask here is whether the way I am casting the i8 is correct comparing to the casting on C end ( (const char*)(unsigned long int)(1) )? 我想问的是,与C端的( (const char*)(unsigned long int)(1) )相比,我投射i8的方式是否正确?

---- EDIT ----- ----编辑-----

Some more details. 一些更多的细节。 Generated PHP binding: 生成的PHP绑定:

#[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,
}

Here an unused struct with some description of this twisted logic: 这是一个未使用的结构,其中包含一些关于这种扭曲逻辑的描述:

/* 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;

Here is the whole macro beig used mormally in c: 这是在c中非正式使用的整个宏指令:

#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 },

And zend_uintptr_t is: zend_uintptr_t是:

typedef uintptr_t zend_uintptr_t;

and then: 接着:

typedef unsigned long int   uintptr_t;

and the struct: 和结构:

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

Your code is not converting an integer to a pointer - as Stargateur says in the comments, the correct way to do that is more simply required_args as *const ::std::os::raw::c_char . 您的代码将整数转换为指针-正如Stargateur在评论中所说,正确的实现方式是required_args as *const ::std::os::raw::c_char

Instead, you are allocating required_args on the heap with Box::new , and then taking it out of the hands of the memory manager with into_raw - giving a pointer to the value of required_args , which, until you manually clean it up, will live forever. 相反,您要使用Box::new在堆上分配required_args ,然后使用into_raw将其移出内存管理器的手-给出指向required_args值的指针,直到您手动将其清除为止永远。

This seem to work with the following test 这似乎适用于以下测试

Because you are dereferencing the pointer into the heap by doing *arguments[0].name , and the value at that pointer is indeed 5 . 因为您通过执行*arguments[0].name将指针解引用到堆中,所以该指针的值确实为5

Unfortunatelly on PHP end (when the code is executed) the value is totally random on every execution. 不幸的是,在PHP端(执行代码时),该值在每次执行时都是完全随机的。

This is unsurprising. 这不足为奇。 Since the end result of your code is that the value of the field is just some pointer into the heap, it will change every time you run the code. 由于代码的最终结果是该字段的值只是指向堆的某个指针,因此每次您运行代码时,它的值都会改变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM