编译器如何看待字符串?

11

C 中,编译器有一个指向字符串开头的指针,并有一个结束符号 ('\0')。如果用户想要计算字符串长度,编译器必须数出字符串数组的元素,直到找到 '\0' 为止。

而在 UCSD-strings 中,编译器将字符串长度存储在前几个字符中。

那么对于 C#-strings,编译器又是如何处理的呢?是的,在用户的角度看来,String 是一个具有字段 Lengthobject,我不是在讲高级东西。我想知道深层次的算法;例如,编译器如何计算字符串的长度?


4
你对 C 语言的假设是错误的。C 编译器可以准确地知道每个字符串的长度。要查看这一点,请调用 sizeof 函数,并将其应用于字符串本身(而不是字符串的指针)。请注意,此操作不会改变原有的含义。 - MSalters
1
通常情况下,我会将此关闭为重复项,但是这些重复项很糟糕。http://www.codeproject.com/Articles/3377/Strings-UNDOCUMENTED - usr
2
@MSalters:我认为homk指的是长度实现(在C中为strlen函数),而不是编译器。 - Cactus Golov
4
你把编译器看到的和执行时发生的混淆了。编译器处理字符串的方式可能与像 strlen 这样的函数处理字符串的方式完全不同,编译时和运行时的表示可能完全不同。 - user2357112
1
在C语言编程中,编译器有一个指向字符串开头的指针,并且有一个终止符('\0')。不是的,在C语言中,编译器有一个起始引号和结束引号。它会将它们之间的字符数作为“sizeof”结果返回,无论它们是什么,包括嵌入的空字符。 strlen()与此无关,指针也不相关。编译器还会在编译后的字符串末尾添加一个空字符。在源文本中并不存在这个字符。 - user207421
显示剩余5条评论
2个回答

21

让我们执行以下代码:

string s = "123";
string s2 = "234";
string s3 = s + s2;
string s4 = s2 + s3;
Console.WriteLine(s + s2);

现在让我们在最后一行设置断点并打开内存窗口:

Strings

在内存窗口中写入s3,我们可以看到2个字符串(s3s4)相继分配,开头有4个字节的大小。

此外,您还可以看到其他分配的内存,例如strings类类型标记和其他string类数据。

string本身包含一个成员private int m_stringLength;,其中包含string的长度,这也使得string.Concat()执行非常快(通过在开始时分配整个长度):

int totalLength = str0.Length + str1.Length + str2.Length;

String result = FastAllocateString(totalLength);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0.Length, str1);
FillStringChecked(result, str0.Length + str1.Length, str2);

我觉得有点奇怪的是,对于string类型的IEnumerable<char>.Count()实现是使用默认实现,这意味着逐个迭代项目,而不像ICollection<T>(如List<T>)那样通过获取其ICollection<T>.Count属性来实现IEnumerable<char>.Count()

2
如果这就是你想知道的,那么你真正的问题与“从编译器的角度来看”毫无关系。 - user207421

7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接