C language Variable length array (ZZ) __c language

Source: Internet
Author: User
An analysis of C-language variable-length arrays

1. Introduction
We know that unlike modern programming languages such as C + +, the traditional C language does not support variable-length array functions, which means that the length of the array is

The compilation period is determined, and cannot be changed during the run time. However, one of the new features in the C99 standard is to allow the use of the variable in the C language

Long array. However, the use of this variable-length array defined by C99 is limited and cannot be used as freely as in languages such as C + +.
2, the description
The description of variable-length arrays in reference [1] is as follows:
C99 gives C programmers the ability to use variable length arrays, which are arrays

Sizes are not known until run time. A variable length array declaration is like a fixed array

Declaration except that's the array size is specified by a non-constant expression. When the

Declaration is encountered, the size expression was evaluated 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 is 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 the containing the declaration

Completes. Each time the "is started", a new array is allocated.
The above is a description of the variable-length array, in addition, in the literature [1] The author also shows that variable-length arrays have the following limitations:
1. Variable-length arrays must be defined within the scope of the program block to define variable-length arrays within the scope of the file;
2. Variable-length arrays can not be modified with static or extern;
3, variable length array can not be a struct or a joint member, only in the form of an independent array;
4. The scope of the variable-length array is the range of blocks, correspondingly, the lifetime of the variable-length array is when the function execution flow exits the block of the variable-length array

Waiting
These limitations are some of the most common constraints, and how to determine the length of variable-length arrays when defining variable-length array types through typedef

, and how to deal with variable-length arrays as function parameters, the author also makes one by one explanations. Please refer to the documentation [1] for detailed details. Because

The length of the variable long array is unknown when the program is compiled, so the memory space of the variable length array is actually allocated in the stack.
Although GCC is considered to be one of the compilers most compliant with the C language standard, it is not implemented in strict accordance with the ISO C standard.

The implementation of GCC takes the strategy of maximizing compliance with standards and extending it from a practical perspective. Of course

GCC provides a compilation option to the consumer to decide whether to use these extension features. There are two types of functionality extensions for GCC, one is GNU's own definition

Language extensions; Another extension is the introduction of the C language feature defined by the C99 standard in C89 mode. In reference [2], the C for GCC

The language extension takes up nearly 120 pages and expands to dozens of language features, which shows how flexible gcc is.
In reference [2], the variable-length array is described as follows:
Variable-length automatic arrays are allowed in ISO C99, and as a 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 are like any other automatic

arrays, but with a length of that are not a constant expression. The storage is allocated at the

Point of Declaration and deallocated then the Brace-level is exited.
The above paragraph does not elaborate on the difference between GCC's variable-length array implementation and ISO C99, but in terms of description,

is basically consistent with the description in document [1]. Some of the points in [2] that are not stated in the literature [1] are: variable-length arrays are

Whether it can be modified with static or extern, whether as a member of a composite type, or whether it works in a file field.
In addition, the Alloca () function can be used to obtain the same effect as a variable-length array, as mentioned in the literature [2]. In the author's Red Hat 9.0 (

Linux 2.4.20-8), this function is defined as a library function:
#include <alloca.h>
void *alloca (size_t size);
This function allocates a size byte space in the stack space of the function that calls it, when the function that calls Alloca () returns or exits

Alloca () The space allocated in the stack is automatically released. When the Alloca () function executes successfully, it returns a pointer to the allocated stack empty

A pointer to the starting address between; However, the very special point is that when the Alloca () function fails, it does not behave like a common library function

Returns a null pointer, which occurs because the stack adjustment in the Alloca () function is usually based on a compilation instruction

Completed, and such an assembly instruction cannot determine whether an overflow has occurred or if a failure has been allocated. Alloca () functions are typically implemented as internal

function, so it is associated with a particular machine and a specific compiler, and portability is thus compromised, and is actually deprecated.


The reason why the author is concerned about the variable-length array is an accidental factor, and it is found that the type of variable-length array given by GDB is very

Weird, which causes the author to test the variable-length array in gcc. The description and analysis of the test results are given in this paper.
3. Example
The source code used for the first test is simple, as follows:
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++) {
arr = (char) (' A ' + i);
11}
Arr[n] = '/0 ';
printf ("%s/n", arr);
14
return (0);
16}
The above program is named Dynarray.c, whose job is to add the value of the parameter argv[1] n plus 1 as the length of the variable length array arr, the variable length array arr class

Type is char. It then writes some characters to the array and outputs the written string.
Compile this program as follows:
[Root@cyc test]# gcc-g-o dynarray dynarray.c
Then, use GDB to observe the implementation of 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) Next
7 Char arr[n+1];
(GDB) Next
8 Bzero (arr, (n+1) * sizeof (char));
(GDB) print/x arr
$ = {0xb0, 0xe5}
(GDB) PType arr
Type = char [2]
(gdb) Print &arr
$ = (char (*) [2]) 0xbfffe1c8
Here, when the program execution stream passes the 7th row of the space allocated for the variable-length array, the ARR value is printed with the print/x command, and the result is

Two bytes, and if you try to print out the Arr type with ptype, the result is arr is an array of characters with a length of 2. It's obvious

In this case, because the argument given to the main () function argv[1] is 6, so it's common sense that arr should be an array of characters with a length of 7.

, but it's a pity that gdb is not giving the result. Print &arr the ARR address as 0XBFFFE1C8. Continue the above tune

Trial process:
(GDB) x/4x &arr
0xbfffe5c8:0xbfffe5b0 0xbfffe5c0 0x00000006 0x40015360
(GDB) x/8x $esp
0xbfffe5b0:0xbffffad8 0x42130a14 0xbfffe5c8 0x0804828d
0XBFFFE5C0:0X42130A14 0x4000c660 0xbfffe5b0 0xbfffe5c0
As you can see, the first 32-bit value at &arr (that is, address 0xbfffe5c8) is 0xbfffe5b0, and through x/8x $esp can be found that the stack

The top pointer esp exactly points to the position of 0xbfffe5b0. So, you can guess, if arr is a pointer, then it points to the

Is exactly the pointer to the top of the current stack. Continue the debugging above:
(GDB) Next
9 for (i = 0; i < n; i++) {
(GDB) Next
arr = (char) (' A ' + i);
(GDB) Next
9 for (i = 0; i < n; i++) {
(GDB) until
Arr[n] = '/0 ';
(GDB) Next
printf ("%s/n", arr);
(GDB) x/8x $esp
0xbfffe5b0:0x44434241 0x42004645 0xbfffe5c8 0x0804828d
0XBFFFE5C0:0X42130A14 0x4000c660 0xbfffe5b0 0xbfffe5c0
Note that the blue part is shown above, because the Intel platform uses a small-endian byte sequence, so the blue part is actually ' ABCDEF '

The hexadecimal representation. The red 32-bit word suggests that arr is the pointer to the top of the stack. To confirm our idea, the following

Modify the value of the ARR to observe the execution of the program (note that the address of the stack at run time is changed):
(GDB) Run
The program being debugged has been started already.
Start it from the beginning? (Y or N) y
Starting Program:/root/source/test/dynarray 6

Breakpoint 1, Main (argc=2, Argv=0xbfffde24) at Dynarray.c:6
6 n = atoi (argv[1]);
(GDB) Next
7 Char arr[n+1];
(GDB) Next
8 Bzero (arr, (n+1) * sizeof (char));
(GDB) print/x &arr
$ = 0xbfffddc8
(GDB) x/8x $esp
0xbfffddb0:0xbffffad8 0x42130a14 0xbfffddc8 0x0804828d
0XBFFFDDC0:0X42130A14 0x4000c660 0xbfffddb0 0xbfffddc0
(GDB) set * (unsigned int*) &arr=0xbfffddc0
(GDB) x/8x $esp
0xbfffddb0:0xbffffad8 0x42130a14 0xbfffddc8 0x0804828d
0XBFFFDDC0:0X42130A14 0x4000c660 0xbfffddc0 0xbfffddc0
(GDB) Next
9 for (i = 0; i < n; i++) {
(GDB) Next
arr = (char) (' A ' + i);
(GDB) Next
9 for (i = 0; i < n; i++) {
(GDB) until
Arr[n] = '/0 ';
(GDB) Next
printf ("%s/n", arr);
(GDB) x/8x $esp
0xbfffddb0:0xbffffad8 0x42130a14 0xbfffddc8 0x0804828d
0xbfffddc0:0x44434241 0x40004645 0xbfffddc0 0xbfffddc0
Address 0xbfffddc8 (that is, arr address) at the value of the original 0xbfffddb0, we changed it to 0xbfffddc0, so, when the process

After the sequence runs to the variable-length array input data, we find that the address of this change is indeed starting from 0xbfffddc0. This means that

Arr Indeed, as we usually understand, the array name is the pointer. Except that the pointer points to the position below it (the stack grows downward

Instead of pointing to a location above as most of the time.
4, analysis
The test results above show that the variable-length array is indeed allocated in the stack space; the array name of the variable-length array is actually an address pointer, meaning

To the top of the stack where the array is located, and GDB cannot determine that the array name of the variable-length array is actually an address pointer.
Why GDB cannot accurately determine the type of variable-length arrays is unclear, but the authors speculate that this is related to the dynamic characteristics of variable-length arrays,

Because the variable-length array is generated by the procedure that the program executes dynamically, GDB cannot be included in the target file as a regular array. Stabs section

Gets the length information, and then gives the wrong type information.
In addition, the scope of the variable-length array is tested, and the test code is modified according to the previous example, as follows:
1 int n;
2 Char arr[n+1];
3
4 int
5 Main (int argc, char *argv[])
6 {
7 int i;
8
9 n = atoi (argv[1]);
Bzero (arr, (n+1) * sizeof (char));
for (i = 0; i < n; i++) {
arr = (char) (' A ' + i);
13}
Arr[n] = '/0 ';
printf ("%s/n", arr);
16
return (0);
18}
When compiled as follows, GCC prompts for an error:
[Root@cyc test]# gcc-g dynarray.c
Dynarray.c:2: Variable-size type declared outside of any function
Visible GCC does not allow variable-length arrays to be defined in the file field.
Whether a variable-length array in GCC can be used with the static modifier is tested with the following code:
1 int
2 main (int argc, char *argv[])
3 {
4 int i, n;
5
6 n = atoi (argv[1]);
7 static char arr[n+1];
8 Bzero (arr, (n+1) * sizeof (char));
9 for (i = 0; i < n; i++) {
arr = (char) (' A ' + i);
11}
Arr[n] = '/0 ';
printf ("%s/n", arr);
14
return (0);
16}
When compiling this source file, GCC gives the following error message:
[Root@cyc test]# gcc-g dynarray.c
dynarray.c:in function ' main ':
Dynarray.c:7: Storage size of ' arr ' isn ' t constant
Dynarray.c:7: Size of variable ' arr ' is too large
According to the hints, it is not possible to declare an array as a variable-length array when it is decorated with static. As for the hint here that arr too large, the author

The reason for guessing is this: for integers, GCC gives a very large value at compile time, which results in a compile error, but only

Just a guess.
Finally, the author is interested in how GCC implements a variable-length array in order to perform these tests. For programming

, you don't have to do this kind of testing, and you don't need to know if the variable length array is in the stack or anywhere else, just know that the variable length array has the above

Some kind of restrictions on the line. In addition, there are many places in this article that are filled with the author's inference and speculation. But it doesn't matter much, it's not

Write a paper, who cares.
In addition, the above test also shows that although the document [2] does not describe the limiting condition of a variable-length array as carefully as in reference [1], it actually

That's the way it works. Once again, GCC did well to comply with the C standard.
Reference documents
[1] Samuel P. Harbison III, Guy L. Steele Jr.; C:a Reference Manual Fifth Edition; Prentice

Hall, Pearson Education, Inc.; 2002
[2] Richard M. Stallman and the GCC Developer Community; Using the GNU Compiler Collection;
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.