一位读者最近问我为什么 C 函数可以返回结构而不是数组。出现这样的问题并不奇怪,因为C语言的数组和结构本质上是在管理一块内存,那为什么编译器会区别对待两者呢?
为什么编译器会以不同的方式处理这两者?
为什么 C 语言函数不能返回数组?
在C语言程序开发中,我们不能编写如下代码:
你不能写这样的代码
这实际上是不能在 C 语言函数中返回数组的事实。但是如果结构体中定义了数组,则可以返回,例如下面的C语言代码,请看:
函数可以返回结构
结构 s 只有一个数组成员 arr。显然,函数可以返回结构体,即使结构体只有一个数组成员,这是为什么呢?
C语言没有严格意义上的“数组类型”
基本上,C语言中的数据结构可以分为两类。第一种数据结构可以赋值,而第二种数据结构不能赋值。数组属于第二种数据结构。
除了数组,还有其他二等数据结构吗?我猜基本上没有,除非你计算功能。
与函数不能返回数组密切相关的是,C语言没有严格意义上的“数组类型”。也许从 C 代码的角度来看,似乎有一个数组类型的变量,但如果您尝试像其他任何变量一样使用该变量,您得到的实际上是指向数组第一个元素的指针。例如,下面的 C 代码:
字符 a[10],b[10];
a = b;
这不会将数组 b 的内容复制到数组 a。其实上面两行C代码等价于下面一行:
a = &b[0];
很明显,左边是数组a,右边其实是一个指针。尽管数组在某种程度上可以被认为是可赋值的,但我们很有可能会出现类型不匹配,例如以下 C 代码:
a = f();
这里假设f()是一个返回数组的函数,其核心C语言代码如下:
字符 ret[10];
/* … 充满 … */
转帐;
不过按照我之前说的,上面的语句其实就相当于下面这句话:
&ret[0];
同样,如果我们尝试将一个数组分配给a,最终的结果仍然是分配一个指向a的指针。熟悉 C 语言语法的读者应该能看出其中的不妥之处。
为什么要把数组塞进,情况不一样
为什么将数组填充到结构中时会有所不同?
文章开头提到,虽然C语言的数组不能赋值,但是插入到结构体中是可以赋值的。这是什么原因?
其实这涉及到C语言的原始设计,以及一些相关的发展历程。C语言在语法和语义上非常接近机器硬件,其基本操作可以编译成一条或多条机器指令,占用几个处理器周期。
C 语言中的数组比较特殊,对指针一直很含糊。这种模棱两可的关系从C语言的前身B语言开始,一直延续到今天,而今天的结构语法原本是没有包含在C语言中的。
因为C语言数组和指针之间的关系模糊,编译器很难区分它们,所以我们不可能给C语言数组赋值。并且由于“赋值”操作也是C语言的基本操作,为了适配硬件,需要在几个处理器周期内完成,所以单个“赋值”操作符=基本不可能扩展为数以千计甚至数万个机器周期为数以千计的数组元素赋值。
基于这个原理,早期的 C 语言甚至不支持结构赋值。
说到这里,相信很多读者都有疑惑。既然C语言的基本操作需要控制在少量的机器周期内,为什么要支持结构赋值呢?毕竟C语言中的结构体也可以包含多个字节的信息。
C语言中的结构也可以包含多个字节
前面说过,早期的C语言不支持结构赋值,但是在后期的开发中,加入了结构赋值的能力。只能说结构是幸运的,“在几个机器周期内控制C语言的基本操作”只是一个指导c定义数组,而不是限制。
要知道C语言的结构通常很小,只有几十到几百个字节。增加结构赋值能力无疑会极大地方便程序员编写代码。在大多数情况下, 赋值操作并不会严重“超时”,这实际上是一种平衡。
正如我在上一篇文章中所讨论的,编程语言一般要处理一个天平,而天平的两端是机器和程序员。如果追求极致的机器效率,把编程语言设计得非常精简c定义数组,那程序员会很痛苦。因此,即使在C语言中,在追求高效率的同时,也必须考虑到程序员的感受,所以违反一些设计原则,增加一些方便的操作也是可以理解的。
概括
C语言不支持数组赋值,更多的原因是C语言本身的特性(适配硬件)和一些历史原因。但是,如果真的要给数组赋值,还是有一些技巧的,比如把数组塞进一个结构体中。这在我之前的文章中已经讨论过,这里不再赘述。
注意
欢迎在评论区讨论和提问。这些文章都是手写的和原创的。每天最简单的C语言、linux等嵌入式开发介绍,喜欢我的文章请关注一波,可以看到最新的更新和以前的文章。
禁止任何未经许可的复制。
文章来源:http://baijiahao.baidu.com/s?id=1647571811934010367&wfr=spider&for=pc