在 C
中,编译器有一个指向字符串开头的指针,并有一个结束符号 ('\0'
)。如果用户想要计算字符串长度,编译器必须数出字符串数组的元素,直到找到 '\0'
为止。
而在 UCSD-strings
中,编译器将字符串长度存储在前几个字符中。
那么对于 C#-strings
,编译器又是如何处理的呢?是的,在用户的角度看来,String
是一个具有字段 Length
的 object
,我不是在讲高级东西。我想知道深层次的算法;例如,编译器如何计算字符串的长度?
在 C
中,编译器有一个指向字符串开头的指针,并有一个结束符号 ('\0'
)。如果用户想要计算字符串长度,编译器必须数出字符串数组的元素,直到找到 '\0'
为止。
而在 UCSD-strings
中,编译器将字符串长度存储在前几个字符中。
那么对于 C#-strings
,编译器又是如何处理的呢?是的,在用户的角度看来,String
是一个具有字段 Length
的 object
,我不是在讲高级东西。我想知道深层次的算法;例如,编译器如何计算字符串的长度?
让我们执行以下代码:
string s = "123";
string s2 = "234";
string s3 = s + s2;
string s4 = s2 + s3;
Console.WriteLine(s + s2);
在内存窗口中写入s3
,我们可以看到2个字符串(s3
和s4
)相继分配,开头有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()
。[NonSerialized]private int m_stringLength;
),它不需要在运行时计算。
String类的源代码可以在线查看。
sizeof
函数,并将其应用于字符串本身(而不是字符串的指针)。请注意,此操作不会改变原有的含义。 - MSaltersstrlen
函数),而不是编译器。 - Cactus Golovstrlen
这样的函数处理字符串的方式完全不同,编译时和运行时的表示可能完全不同。 - user2357112strlen()
与此无关,指针也不相关。编译器还会在编译后的字符串末尾添加一个空字符。在源文本中并不存在这个字符。 - user207421