[疑难] 菜鸟提问题
Colorful
2007-05-30
发现一个挺有意思的事情。废话不多说,直接上代码。
int main(char[][] argv) { const char[] stringA = "Hello"; // 在默认代码段申请一块只读内存 char[] stringB = stringA; // stringB保存的内存地址跟stringA并不一致 printf("stringA's Address = 0x%X\n", stringA.ptr); printf("stringB's Address = 0x%X\n", stringB.ptr); //stringA[1] = 'Q'; // 编译器在编译期保证stringA只读 /* 看我指针大法 */ char* pointer = stringA.ptr; pointer[1] = 'Q'; pointer = null; printf("\n"); printf("stringA = \"%s\"\n", cast(char*)stringA); // stringA = "HQllo",内容已更改 printf("stringA = \"%*s\"\n", stringA); // stringA = "Hello",内容未更改 printf("\n"); /* 为了避免是否强制类型转换导致内容不一致,测试一下(其实是没理由的测试) */ char* tempString = cast(char*)stringA; printf("tempString's Address = 0x%X\n", tempString); // 地址与stringA相同 printf("tempString = \"%s\"\n", tempString); // 内容也相同 printf("\n"); /* stringB中的内容丝毫未动 */ printf("stringB = \"%s\"\n", cast(char*)stringB); printf("stringB = \"%*s\"\n", stringB); stringB[2] = 'W'; // 修改stringB中的内容 printf("\n"); /* 下面的结果比上面的还精彩 */ printf("stringA = \"%s\"\n", cast(char*)stringA); // stringA = "HQllo" printf("stringA = \"%*s\"\n", stringA); // stringA = "HeWlo" printf("stringB = \"%s\"\n", cast(char*)stringB); // stringB = "HeWlo" printf("stringB = \"%*s\"\n", stringB); // stringB = "HeWlo"; return 0; } 问题1: 为什么用指针修改stringA内容之后,stringA的结果会不一致? 问题2: 为什么修改stringB内容之后,stringA也会跟着改变? 一开始,我以为stringB是stringA的切片,但是当stringA内容改变时,stringB内容却不曾改变。接下来,我以为编译器可能知道stringA只读,所以给stringB另外申请了一块内存,复制其内容。但是修改stringB内容时,stringA内容也跟着改变了. 望前辈们不吝赐教. |
|
Colorful
2007-05-30
附加一个问题。
关于Copy on Write机制,D文档里给出的示例,俺没有看明白,还请达人给指点迷津。 我对Copy on Write的理解是这样的: 这个东东实际上就是延迟分配内存,只有到你要修改其内容的时候才去申请新内存。这样做的好处就是提升性能和减少内存占用。 不知道理解的对不对,呵呵。 |
|
oldrev
2007-05-30
1. char[] stringB = stringA; 这句是深拷贝,等价于
char[] stringB = "Hello"; //为 stringB 赋初值 2. 首先,试图修改 const 的值是未定义的行为。其次,const char[] stringA 与 stringA.ptr 类型并不相同,const char[] stringA 是编译时常量,compiler 怎么处置是它自己的事。 3. doc 里的COW值的不是数组实现了COW,而是Phobos 里的数组操作函数实现了COW。这些函数如果没有修改源数组的值就返回源数组,但是这有一定的危险性,如: import std.stdio; import std.string; void main(char[][] argv) { char[] a = "ABCDE"; char[] b = toupper(a); b[0] = 'S'; //这将导致源数组 a 被修改 writefln(a); } |
|
Colorful
2007-05-30
晕,我把const最原始的定义给忘了,哈哈。
面壁...... |
|
achun
2007-05-30
oldrev 写道 import std.stdio; import std.string; void main(char[][] argv) { char[] a = "ABCDE"; char[] b = toupper(a); b[0] = 'S'; //这将导致源数组 a 被修改 writefln(a); } 不对吧! import std.stdio; import std.string; void main(char[][] argv) { char[] a = "abcde"; char[] b = toupper(a); char[] c = a.dup;//dup 创建一个同样大小的动态数组并将原数组的内容复制到新数组中。 char[] d = a; b[0] = 'S'; writefln(a);//print abcde c[0] = 'S'; writefln(a);//print abcde d[0] = 'S'; writefln(a);//print Sbcde } |
|
oldrev
2007-05-30
什么不对?"ABCDE" 没被 toupper(a) 修改,返回的仍然是 a。
程序运行后显示 "SBCDE" |
|
achun
2007-05-30
你吧
char[] a = "ABCDE"; 改成 char[] a = "abcde"; 我有些不明白了,这个toupper的行为正常么? |
|
oldrev
2007-05-30
这就是 COW
|
|
achun
2007-05-30
又仔细的看了一下DOC,里面正好是toupper的原代码,和string.d里的基本一致.
果然是COW 也就是说,在COW下, 如果程序绝对希望对数据进行真正的COPY 赋值, 就像上面的那样,那就要自己手工代码保证, 也就是 类似 dup 的操作了. 汗,我..... DOC看的不仔细呀.... 规则没有搞清楚呀.... 这次印象深刻了. 另外发现string.d里的toupper里有 r[i] = cast(char) (c - (cast(char)'a' - 'A')); 猛一看似乎觉得效率低,又一想.... 明白了. 1.(cast(char)'a' - 'A') 可能会被编译器优化直接计算成一个固定值 2.这就是标准库的写法呀 谁说平台一定用ASCII编码的? 比如IBM的有些系统平台就不是ASSCII编码, 不过这算法只适合 abcd...z连续,ABCD...Z也连续的规则 如果是aAbB...zZ的编码规则这个算法还是要错的. |
|
oldrev
2007-05-30
程序内部使用什么编码根系统平台有什么关系?
|