So i was just tinkering with C libs in Rust and i found that the following code:
extern crate libc;
use libc::{c_char, c_int, size_t};
extern "C" {
fn printf(fmt: *const c_char, ...) -> c_int;
fn strlen(arr: *const c_char) -> size_t;
}
fn main() {
unsafe {
printf("This uses C's standard lib printf".as_ptr() as *const i8);
print!("\n");
let s = "Useless thing again";
print!("Length of {}: ", s);
let x = strlen(s.as_ptr() as *const i8);
print!("{}", &x);
}
}
Will produce this:
This uses C's standard lib printf
Length of Useless thing again: 31
strlen() also counted the string slice inside print! macro. But if i do this:
extern crate libc;
use libc::{c_char, c_int, size_t};
extern "C" {
fn printf(fmt: *const c_char, ...) -> c_int;
fn strlen(arr: *const c_char) -> size_t;
}
fn main() {
unsafe {
printf("This uses C's standard lib printf".as_ptr() as *const i8);
print!("\n");
print!("blah blah blah\n");
let s = "Useless thing again";
let x = strlen(s.as_ptr() as *const i8);
print!("{}", &x);
}
}
It will produce this:
This uses C's standard lib printf
blah blah blah
19
It counted "Useless thing again" correctly and won't count anything above s variable. I know it probably has some kind of connection with memory but i am actually quite new to low level. Can i have some detailed explanations?
'\0' = 0) to indicate the end of a string (char*). Because of this behavior, all string literals in C have an implicit null character. However, since Rust opts to store the length of strings at runtime like C++'sstd::string, the null character is no longer needed. Once compiled, these strings are stored in the text section of the binary file. In order to save space, the compiler omitted the null character and likely put all of the string literals together.printfthe character pointer from the first example (or look at the text section of the binary file) it would look something like this:"Useless thing againLength of : "printfand Rust'sprint!use different buffers. The string sent toprintfmight beThis uses C's standard lib printf\nUseless thing againLength of :(just all the literals joined together), but only up to the\nwill be printed by C, and Rust doesn't know about C's stdout buffer, so the rest will just be left there. The Rust compiler is almost certainly not injecting null bytes "for safety" (although it's anyone's guess why the second program seems to work properly).printfdoesn't stop at the end of the string because there's an empty line in the output beforeLength of Useless thing again-- that's the same\nbeing printed twice, first by C and then by Rust.