Declaring a variable-length array as a global variable in C

How can a variable-length array be declared as a global variable?

when a variable-length array is declared in a function before scanning the length, it compiles, but does not start. it gives a segmentation error. when the same ad statement moves below the crawl instruction, it works fine.

if we want a variable-length array to be globally accessible for all functions, how can we do this? the problem is that the length of the array can only be checked with some function.

+9
source share
4 answers

You cannot do this. Here is what the draft standard says:

6.7.6.2 Manifest declaration

2 If an identifier is declared as having a changed type, it must be a regular identifier (as defined in 6.2.3), they do not and do have either the scope of the block or the scope of the function prototype. If the identifier is declared as an object with a static or storage time stream, it should not have an array type of variable length.

Besides,

10 EXAMPLE 4 All declarations of variables of changed types (VM) should be both in the block area and in the scope of the prototype. Array objects declared with _Thread_local, static, or extern The storage class specifier cannot be of variable length type (VLA). However, an object declared using a static storage specifier can have a virtual machine type (that is, a pointer to a VLA type). Finally, all identifiers declared with type VM must be regular identifiers and therefore cannot be members of structures or unions.

+3
source

An array of variable length (i.e. the size of an array with a run-time value) cannot be a global variable, because the expression you use for size should obviously be computed at compile time. He can only live on the stack. Presumably what you get is a static array with a size that depends on where in the code you define it (because you are redefining something it depends on).

Why can't you just use the global pointer and realloc () to size it as needed?

+4
source

It is impossible to declare an array of variable length as a global variable in C, since it would have to be allocated before it knew its size so that the compiler could not know how much memory it should allocate for it. However, you can (and should) do this dynamically:

char* my_dynamic_array = NULL; void f(unsigned int size) { if(!my_dynamic_array) { my_dynamic_array = malloc(size); } /* do something with the array */ } int main(void) { f(1024); /* set size dynamically */ /* do something with the array */ free(my_dynamic_array); /* free the allocated memory */ return 0; } 
+2
source

Hum responded to this 7 years after the discovery. Contrary to the answer to this question, there is hope for bold devils :).

I came across this necessity by sharing a global VLA (dyn array, etc.) in a multi-threaded application. A short story, I need my thread to share the global array, I will postpone synchronization / cache issues here, since I just want to show how to use VLA, this example can be output for other needs (for example, for an external VLA, etc. ...)

Here is the code, followed by an annotation explaining why this works.

 #include <pthread.h> #include <stdio.h> #include <stdlib.h> int gn, gm, *ga; /* (*2) */ void worker(int tndx, long n, long m, int a[n][m]) /* (*6) */ { long *np=&n, *mp=&m, i=mp-np, *ap=mp+i; /* (*7) */ *ap=(long)ga; /* At this oint the worker can elegantly access the global dyn array. * elegantly mean through a[i][j]. */ printf("worker %d started\n", tndx); for(int j=0;j<m;j++) { a[tndx][j]+=(tndx*1000); /* (*8) */ } } void *init_thread(void *v) { int x[1][1], tndx = (int)(long)v; /* (*4) */ printf("thread #%d started\n", tndx); worker(tndx, (long)gn, (long)gm, x); /* (*5) */ return(0); } int main(int ac, char **av) { int n=atoi(av[1]), m=atoi(av[2]); pthread_t tt[n]; /* thread table */ /* (*1) */ int a[n][m]; /* dyn array */ /* (*1) */ gn=n, gm=m, ga=&a[0][0]; /* globals setup shared by workers */ /* (*2) */ for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++)a[i][j]=k++; /* (*3) */ printf("Init a[][]\n"); for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++) printf("a[%d][%d]=%d\n",i,j,a[i][j]); for(int i=0;i<n;i++) { if(pthread_create(&tt[i], NULL, init_thread, (void *)(long)i)) { exit((printf("pthread_create %d failed\n",i),1)); } } printf("Draining threads\n"); for(int i=0;i<n;i++) { pthread_join(tt[i],0); } printf("Final a[][]\n"); for(int i=0, k=0;i<n;i++)for(int j=0;j<m;j++) printf("a[%d][%d]=%d\n",i,j,a[i][j]); pthread_exit(NULL); } 

(* 1) Here we declare a VLA, the execution line will determine the number of threads, as well as the size of our 2 dim VLA, n lines (1 per thread) with m values โ€‹โ€‹in each.

(* 2) We declare (en setup) our global VLA, we expose our global n and m (like gn, gm) and our global array as a pointer to the scalar type of the array (here int), we start to point to a [0 ] [0].

(* 3) we set the values โ€‹โ€‹to [n] [m] (sequentially int, 0, 1, 2, ...)

(* 4) All threads are started using init_thread (), note that we declare a dummy array of the same type as our [n] [m] VLA, the goal here is to pass an array compatible with our worker () API.

(* 5) Our employee needs a long type for n, m (dim), this is explained in (* 6), so here we pass global n and m to our processed and dummy array, we donโ€™t care about that, the only goal is to pass the array addr as an argument.

(* 6) A working API, we have several arguments (for example, tndx), then we have a VLA, denoted by long, n, long m, int a [n] [m]. At this point, a [] [] is x [] [] and is not useful.

We used long for n and m to correct the unexpected appearance of the stack, then n, m and a are glued together, because we take addr from n and m, that is, the arguments that are in the register (modern arch) are pushed onto the stack in their placeholders , I = mp = np, take care of determining the direction of the stack (arg0, arg1, arg2), at this moment we can access the base address x [] [] and put our global ga there * ap = (long) ha;

(* 8) Now our employees can elegantly access the global (shared) VLA.

Here is a run

 VY$ cc -o t2 t2.c -lpthread VY$ ./t2 3 4 Init a[][] a[0][0]=0 a[0][1]=1 a[0][2]=2 a[0][3]=3 a[1][0]=4 a[1][1]=5 a[1][2]=6 a[1][3]=7 a[2][0]=8 a[2][1]=9 a[2][2]=10 a[2][3]=11 thread #0 started worker 0 started thread #2 started worker 2 started thread #1 started worker 1 started Draining threads Final a[][] a[0][0]=0 a[0][1]=1 a[0][2]=2 a[0][3]=3 a[1][0]=1004 a[1][1]=1005 a[1][2]=1006 a[1][3]=1007 a[2][0]=2008 a[2][1]=2009 a[2][2]=2010 a[2][3]=2011 

Each thread changed its line by adding ID * 1000.

In this way, we can definitely determine the globality of VLA.

VLA is cool except for the need for the student to read about alloca (), etc., but there is a need for a global one, and as explained at compile time, this is not possible, but GCC (libgcc?) Should be able to offer an API "fix" VLA base address at run time.

Iโ€™m now that many will speak out against taking arg addr, hacking the direction of the stack, etc., but many other codes work like this: va_args, alloca, etc. So it may look ugly, but this ugliness can be hidden .

Hooray fi

0
source

All Articles