在尝试理解堆栈内存的工作原理时,我编写了以下代码来显示数据存储位置的地址:
fn main() {
let a = "0123456789abcdef0";
let b = "123456789abcdef01";
let c = "23456789abcdef012";
println!("{:p} {}", &a, a.len());
println!("{:p} {}", &b, b.len());
println!("{:p} {}", &c, c.len());
}
输出结果为:
0x7fff288a5448 17
0x7fff288a5438 17
0x7fff288a5428 17
这意味着所有17个字节都存储在16个字节的空间中,这是不对的。我的猜测是有一些优化正在发生,但即使我使用--opt-level 0
进行构建,我也会得到相同的结果。
等效的C似乎做得对:
#include <stdio.h>
#include <string.h>
int main() {
char a[] = "0123456789abcdef";
char b[] = "123456789abcdef0";
char c[] = "23456789abcdef01";
printf("%p %zu\n", &a, strlen(a) + 1);
printf("%p %zu\n", &b, strlen(b) + 1);
printf("%p %zu\n", &c, strlen(c) + 1);
return 0;
}
输出:
0x7fff5837b440 17
0x7fff5837b420 17
0x7fff5837b400 17
答案 0 :(得分:7)
字符串文字"..."
存储在静态内存中,变量a
,b
,c
只是(胖)指针。它们的类型为&str
,具有以下布局:
struct StrSlice {
data: *const u8,
length: uint
}
其中data
字段指向形成文本的字节序列,length
字段指示有多少字节。
在64位平台上,这是16字节(在32位平台上,8字节)。 C中的实际等价物(忽略空终止与存储长度)将存储到const char*
而不是char[]
,将C更改为此打印:
0x7fff21254508 17
0x7fff21254500 17
0x7fff212544f8 17
即。指针相隔8个字节。
您可以使用--emit=asm
或--emit=llvm-ir
或点击corresponding button on the playpen检查这些底层详细信息(也可能会调整优化级别)。 E.g。
fn main() {
let a = "0123456789abcdef0";
}
使用--emit=llvm-ir
编译并且没有优化(使用我的修剪和注释):
%str_slice = type { i8*, i64 }
;; global constant with the string's text
@str1042 = internal constant [17 x i8] c"0123456789abcdef0"
; Function Attrs: uwtable
define internal void @_ZN4main20h55efe3c71b4bb8f4eaaE() unnamed_addr #0 {
entry-block:
;; create stack space for the `a` variable
%a = alloca %str_slice
;; get a pointer to the first element of the `a` struct (`data`)...
%0 = getelementptr inbounds %str_slice* %a, i32 0, i32 0
;; ... and store the pointer to the string data in it
store i8* getelementptr inbounds ([17 x i8]* @str1042, i32 0, i32 0), i8** %0
;; get a pointer to the second element of the `a` struct (`length`)...
%1 = getelementptr inbounds %str_slice* %a, i32 0, i32 1
;; ... and store the length of the string (17) in it.
store i64 17, i64* %1
ret void
}