设为首页 加入收藏

TOP

C语言变长数组之剖析(一)
2014-11-24 03:14:26 来源: 作者: 【 】 浏览:1
Tags:语言 剖析

1、引言
我们知道,与C++等现代编程语言不同,传统上的C语言是不支持变长数组功能的,也就是说数组的长度是在编译期就确定下来的,不能在运行期改变。不过,在C99标准中,新增的一项功能就是允许在C语言中使用变长数组。然而,C99定义的这种变长数组的使用是有限制的,不能像在C++等语言中一样自由使用。


2、说明
参考文献[1]中对变长数组的说明如下:


C99 gives C programmers the ability to use variable length arrays, which are arrays whose sizes are not known until run time. A variable length array declaration is like a fixed array declaration except that the array size is specified by a non-constant expression. When the declaration is encountered, the size expression is eva luated and the array is created with the indicated length, which must be a positive integer. Once created, variable length array cannot change in length. Elements in the array can be accessed up to the allocated length; accessing elements beyond that length results in undefined behavior. There is no check required for such out-of-range accesses. The array is destroyed when the block containing the declaration completes. Each time the block is started, a new array is allocated.


以上就是对变长数组的说明,此外,在文献[1]中作者还说明,变长数组有以下限制:


1、变长数组必须在程序块的范围内定义,不能在文件范围内定义变长数组;


2、变长数组不能用static或者extern修饰;


3、变长数组不能作为结构体或者联合的成员,只能以独立的数组形式存在;


4、变长数组的作用域为块的范围,对应地,变长数组的生存时间为当函数执行流退出变长数组所在块的时候;


上述限制是最常见的一些限制因素,此外,当通过typedef定义变长数组类型时,如何确定变长数组的长度,以及当变长数组作为函数参数时如何处理,作者也做了一一说明。详细的细节情况请参阅文献[1]。由于变长数组的长度在程序编译时未知,因此变长数组的内存空间实际上是在栈中分配的。


gcc虽然被认为是最遵守C语言标准的编译器之一,但是它并不是严格按照ISO C标准规定的方式来实现的。gcc的实现方式采取了这样的策略:最大限度地遵守标准的规定,同时从实用的角度做自己的扩展。当然,gcc提供了编译选项给使用者以决定是否使用这些扩展功能。gcc的功能扩展分为两种,一种是gnu自己定义的语言扩展;另外一种扩展是在C89模式中引入由C99标准定义的C语言特性。在参考文献[2]中,有关gcc的C语言扩展占据了将近120页的篇幅,扩展的语言功能多达几十个,由此可看出gcc的灵活程度。


在参考文献[2]中,对变长数组的描述如下:


Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C89 mode and in C++. (However, GCC’s implementation of variable-length arrays does not yet conform in detail to the ISO C99 standard.) These arrays are declared like any other automatic arrays, but with a length that is not a constant expression. The storage is allocated at the point of declaration and deallocated when the brace-level is exited.


以上这段话并没有详细的说明gcc的变长数组实现和ISO C99的差异究竟体现在什么地方,但是从描述来看,基本上和文献[1]中的描述是一致的。文献[2]中没有说明而在文献[1]中给予了说明的几点是:变长数组是否能用static或者extern修饰;能否作为复合类型的成员;能否在文件域起作用。




#include



void *alloca(size_t size);



这个函数在调用它的函数的栈空间中分配一个size字节大小的空间,当调用alloca()的函数返回或退出的时候,alloca()在栈中分配的空间被自动释放。当alloca()函数执行成功时,它将返回一个指向所分配的栈空间的起始地址的指针;然而,非常特别的一点是,当alloca()函数执行失败时,它不会像常见的库函数那样返回一个NULL指针,之所以会出现这样的状况,是由于alloca()函数中的栈调整通常是通过一条汇编指令来完成的,而这样一条汇编指令是无法判断是否发生溢出或者是否分配失败的。alloca()函数通常被实现为内联函数,因此它是与特定机器以及特定编译器相关联的,可移植性因此而大打折扣,实际上是不推荐使用的。



作者之所以会关注变长数组的问题是出于一次偶然的因素,在调试的时候发现gdb给出的变长数组的类型很怪异,由此引发作者对gcc中的变长数组进行了测试。本文中给出的就是对测试结果的说明和分析。



3、实例
第一个测试所用的源代码很简单,如下所示:


1 int


2 main(int argc, char *argv[])


3 {


4 int i, n;


5


6 n = atoi(argv[1]);


7 char arr[n+1];


8 bzero(arr, (n+1) * sizeof(char));


9 for (i = 0; i < n; i++) {


10 arr[i] = (char)('A' + i);


11 }


12 arr[n] = '';


13 printf("%sn", arr);


14


15 return (0);


16 }


上述程序名为dynarray.c,其工作是把参数argv[1]的值n加上1作为变长数组arr的长度,变长数组arr的类型为char。然后向数组中写入一些字符,并将写入的字符串输出。


像下面这样编译这个程序:


[root@cyc test]# gcc -g -o dynarray dynarray.c



然后,用gdb观察dynarray的执行情况:


[root@cyc test]# gdb dynarray



(gdb) break main



Breakpoint 1 at 0x80483a3: file dynarray.c, line 6.


(gdb) set args 6



(gdb) run



Starting program: /root/source/test/a.out 6




Breakpoint 1, main (argc=2, argv=0xbfffe224) at dynarray.c:6


6 n = atoi(argv[1]);


(gdb

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇GNU C中的数组类型 下一篇Linux内核基础--事件通知链(notif..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·Python中文网 - 人生 (2025-12-24 18:49:47)
·【整整648集】这绝对 (2025-12-24 18:49:44)
·Python超详细一条龙 (2025-12-24 18:49:42)
·【超详细】JDK 下载 (2025-12-24 18:19:32)
·Java_百度百科 (2025-12-24 18:19:29)