- 论坛徽章:
- 0
|
深深佩服楼主的研究精神和用词的专业性。
但我觉得从编译器的角度去解释这些事情太吃力不讨好了,太晦涩了,事实上对非编译器开发者的程序员来说也是没有多大意义的。
对于数组的声明,我的理解可能没那么专业,但很实用。
有些语言的数组声明比c语言的更直观一些,比如java中可以这样声明一个数组按照自然的方式从左往右读,int是基本类型,[]是扩展类型,a是标识符
go语言声明一个数组正好跟java是反着的,但也是很直观的- var x int = 1;//声明并定义一个int型变量
- var x [5]int; //go语言声明一个int型数组
复制代码 从左往右读,就是: 一个变量var,它的名字叫x,它的类型是,长度是5的数组扩展类型[],再加上一个int类型,也就是一个扩展类型。
反观c语言,基本类型和扩展类型没有放在一起,而是被中间一个标识符隔开了,为什么c语言这么反直觉的
我记得跟网友交流的时候,谈到一个c语言的设计哲学,那就是让声明的形式和使用的形式一致。比如你看到它的声明,就知道该怎么使用它, 用跟声明一样的形式就是a[1]表示一个int
读这个声明的时候,就这样去思考,a通过每一个下标运算符计算(或者叫做偏移)的数据类型是int型的,实际上a是内存上一段连续的数据块,这个数据块的粒度就是int,这个数据块的界限是5,界线以外的都是不可控的。
理解了内存模型,也就理解了c语言最难懂的指针。而不用去费尽心机去研究编译器是怎么解释它的。
再谈谈指针跟数组的关系,在大多数情况下,指针跟数组是没有任何联系,他们有时候使用方式类似,那是他们面对的内存模型是一致的
唯一把数组跟指针关联在一块的是,当函数的参数为一个数组或指针,而你传的实参是一个数组首地址的时候,编译器就会把这个首地址拷贝一份,放到一个指针变量里,也就是形参里的那个副本
有的书里面说,这是数组到指针的退化
为什么要这么做,楼主也说的很清楚了,编译器完全可以把整个数组的数据拷贝到栈里,作为形参副本
但是为了效率上的原因,编译器只好跟程序员“约定”,数组就在那个地方,它的地址存放在这个指针里,你通过这个指针去操作吧
就这样只是一个约定
到底什么是指针,去稍微学点汇编,了解下cpu的内存管理,就彻底搞懂了。
|
|