你如何将 Rust 中的整数转换为 C 中的 char*
How do you cast integer in Rust to char* in C
我有以下用例。 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 结束时(当代码被执行时),每次执行的值都是完全随机的。
这里想问的是我i8的投法和C端的投法((const char*)(unsigned long int)(1)
)相比是否正确?
---- 编辑 -----
更多细节。已生成 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,
}
这是一个未使用的结构,其中包含对这种扭曲逻辑的一些描述:
/* 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::raw::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.
这不足为奇。由于您的代码的最终结果是该字段的值只是一些指向堆的指针,因此每次您 运行 代码时它都会改变。
我有以下用例。 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 结束时(当代码被执行时),每次执行的值都是完全随机的。
这里想问的是我i8的投法和C端的投法((const char*)(unsigned long int)(1)
)相比是否正确?
---- 编辑 -----
更多细节。已生成 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,
}
这是一个未使用的结构,其中包含对这种扭曲逻辑的一些描述:
/* 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::raw::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.
这不足为奇。由于您的代码的最终结果是该字段的值只是一些指向堆的指针,因此每次您 运行 代码时它都会改变。