第一个字节在转换为CString时突然变为零。

huangapple go评论64阅读模式
英文:

First byte is suddenly zeroed while converting to CString

问题

Here is the translated code part you provided:

我想要进行 FFI 调用。为了这样做,我需要将 Rust 字符串转换为以适当编码为零结尾的 C 字符串。我编写了这段代码,但不知何故它会将第一个字节替换为零。为什么会发生这种情况?如何修复这个问题?

使用编码::所有::WINDOWS_1251
使用编码::{EncoderTrap, Encoding}
使用 std::ffi::{c_char, CString}

fn str_to_c_str(input&str- > *const c_char {
     enc_inputVec < u8 > = WINDOWS_1251.encode(inputEncoderTrap::Strict.expect("TODO:panic message");
    println!("enc_input {:?}", enc_input);
     cstringCString = CString::new(enc_input.expect("TODO:panic message");
     s1 = 不安全 {std::slice::from_raw_parts(cstring.as_ptr()4};
    println!("str_to_c_str {:?}", s1);
    cstring.as_ptr()
}

fn main(){
    不安全 {
         data = str_to_c_str("ABC");
         s2 = 不安全 {std::slice::from_raw_parts(data4};
        println!("main {:?}", s2);
    }
}
[dependencies]
libc = "0.2.0"
encoding = "0.2"
byteorder = "1.4.3"

如果我像这样重写我的代码,它会有效吗?就像编译器看到在 1 之后没有对 data 的“有效”使用,并且在 CString 中没有自定义释放器,或者没有可见的副作用,编译器是否可以将 data 的释放从 2 移动到 1 作为优化?

使用编码::所有::WINDOWS_1251
使用编码::{EncoderTrapEncoding}
使用 std::ffi::{c_charCString}

不安全 fn ffi_callarg*const c_char- > () {
     s1 = 不安全 {std::slice::from_raw_parts(arg4};
    println!("str_to_c_str {:?}", s1);
}

fn str_to_c_strinput&str- > CString {
     enc_inputVec < u8 > = WINDOWS_1251.encode(inputEncoderTrap::Strict.expect("TODO:panic message");
    println!("enc_input {:?}", enc_input);
     cstringCString = CString::new(enc_input.expect("TODO:panic message");
    cstring
}

fn main(){
     data = str_to_c_str("ABC");
    // 1
    不安全 {
        ffi_call(data.as_ptr());
    }
    // 2
}
英文:

I want to do FFI call. To do so i need to convert a Rust string into C-zero-terminated-string in a proper encoding. I wrote this code but somehow it replaces first byte with zero. Why this happen? How do I fix this?

use encoding::all::WINDOWS_1251;
use encoding::{EncoderTrap, Encoding};
use std::ffi::{c_char, CString};

fn str_to_c_str(input: &amp;str) -&gt; *const c_char {
    let enc_input: Vec&lt;u8&gt; = WINDOWS_1251.encode(input, EncoderTrap::Strict).expect(&quot;TODO: panic message&quot;);
    println!(&quot;enc_input {:?}&quot;, enc_input);
    let cstring: CString = CString::new(enc_input).expect(&quot;TODO: panic message&quot;);
    let s1 = unsafe { std::slice::from_raw_parts(cstring.as_ptr(), 4) };
    println!(&quot;str_to_c_str {:?}&quot;, s1);
    cstring.as_ptr()
}

fn main() {
    unsafe {
        let data = str_to_c_str(&quot;ABC&quot;);
        let s2 = unsafe { std::slice::from_raw_parts(data, 4) };
        println!(&quot;main {:?}&quot;, s2);
    }
}

Here is an actual output:

enc_input [65, 66, 67]
str_to_c_str [65, 66, 67, 0]
main [0, 66, 67, 0]

I expect a last line to be:

main [65, 66, 67, 0]

[dependencies]
libc = &quot;0.2.0&quot;
encoding = &quot;0.2&quot;
byteorder = &quot;1.4.3&quot;

Added

If I rewrite my code like this would it be valid?
Like if a compiler see that there is no "valid" usage of data after 1 and there is no custom deallocator in CString or is has no visible side-effect, can the compiler move data's deallocation from 2 to 1 as an optimisation?

use encoding::all::WINDOWS_1251;
use encoding::{EncoderTrap, Encoding};
use std::ffi::{c_char, CString};

unsafe fn ffi_call(arg: *const c_char) -&gt; () {
    let s1 = unsafe { std::slice::from_raw_parts(arg, 4) };
    println!(&quot;str_to_c_str {:?}&quot;, s1);
}

fn str_to_c_str(input: &amp;str) -&gt; CString {
    let enc_input: Vec&lt;u8&gt; = WINDOWS_1251.encode(input, EncoderTrap::Strict).expect(&quot;TODO: panic message&quot;);
    println!(&quot;enc_input {:?}&quot;, enc_input);
    let cstring: CString = CString::new(enc_input).expect(&quot;TODO: panic message&quot;);
    cstring
}

fn main() {
    let data = str_to_c_str(&quot;ABC&quot;);
    // 1
    unsafe {
        ffi_call(data.as_ptr());
    }
    // 2
}

答案1

得分: 1

"不允许,因为这会导致程序出现错误。只要您的代码没有未定义行为,您无需担心编译器优化。如果编译器优化会导致程序出错,那将是编译器的错误(这种情况相当罕见)。”

英文:

> If I rewrite my code like this would it be valid? Like if a compiler see that there is no "valid" usage of data after 1 and there is no custom deallocator in CString or is has no visible side-effect, can the compiler move data's deallocation from 2 to 1 as an optimisation?

No, it is not allowed to, exactly because this will break your program.

As long as you don't have UB in your code, you don't have to worry about compiler optimizations. If they will break your program, it will be a bug in the compiler (and it's pretty rare).

huangapple
  • 本文由 发表于 2023年5月17日 17:46:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76270723.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定