编译器:字符串常量与动态分配的字符串对象

Compiler: String constant vs dynamically-allocated String object

我正在编写一个小型编译器,但在处理字符串常量和字符串对象时遇到问题。

以下面的代码为例:

s : String = "Hello world"

由于字符串在程序中,这会被编译器识别并生成一个字符串常量放在.data

.data

string_const1:
    .quad    2
    .quad    6
    .quad    String_dispatch_table
    .quad    int_const1
    .asciz    "Hello world"
    .align    8

然后可以通过以下方式访问实际字符串:

leaq string_const1(%rip), %rax
addq , %rax

但是,如果我们要求用户输入一个字符串,那么这个字符串对象就需要动态生成。这里是同样放在 .data 段中的字符串对象模板。

String_protoObj:
    .quad    2                        # tag              
    .quad    5                        # size
    .quad    String_dispatch_table    
    .quad    0                        # string length
    .quad    0                        # string content

# assume %rax contains the address of a copy of String_protoObj
# assume %rdi contains the address of user input string 

leaq String_protoObj(%rip), %rdi
callq malloc
movq user-input, %rdi
movq %rdi, 32(%rax)   # copy the new string into string content

然后要访问实际的字符串,我必须使用

32(%rax)  # read from memory

因此从字符串常量和动态分配的字符串对象访问字符串是有区别的,这需要在所有函数中使用不同的句柄

我显然可以在 protoObject 中添加另一个标记来指示这是一个分配的对象而不是常量,但这需要所有接收字符串 object/constant 的方法进行检查,这听起来不太优雅完全没有。

谁能给我一些建议,我该如何处理好这种情况?

就个人而言,我会首先让常量看起来像一个字符串对象,这意味着第五个单词将包含指向第六个单词的指针。这是您显然愿意为字符串对象支付的价格。

一种更 space 有效的策略是大多数现代 C++ 库使用的策略,其中有两种字符串布局:一种包含字符向量(短字符串),另一种包含指针。你可以根据长度来区分它们,这样你就不需要不同的标签,当然你也可以使用不同的标签。

在实践中,大多数字符串都相当短,因此这种优化被认为是有用的。但它的工作量更大,要编写的测试也更多,因此您可能希望将其保存以备后用。