variable length array (VLA) reference (global, extern access, etc)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi All,

I have a need for a VLA reference to be saved globally so unrelatted
functions could retrieve the VLA global ref (dim values along with scalar
addr of the 1st array element) and could then 'construct' its own VLA for
an 'elegant' multi-dimensional array access.

While storing a VLA reference a relativly easy (store the addr of
a[0][0]... or simply &a), declaring a VLA in an unrelated function is more
tricky but doable. I wanted to know if there is a way with gcc to kind of
change a VLA base addr dynamically through an API.

I presented a solution I found to fit my need, that is sharing a
multi-dimentional array between main() VLA creation, and init, then VLA
reference publishing in the global scope, and finally spawing threads that
can use the global VLA ref to setup their own VLA, all accessing the same
VLA from main(). I ignored the synchro/cache access on purpose in the
example because it is not relevant for the demo.

https://stackoverflow.com/questions/10360394/declaring-a-variable-length-array-as-a-global-variable-in-c/56924075#56924075

The code is like this /* (*N) */ are reference to comment I provide in the
above document.


#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) */
}

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);
}

So you see in the above example, I use a 'tiny' or 'moderate' hack to patch
the base addr of the threads VLA, doing trivial stack inspection and patch.

So my question is about avoiding the hack, is there a way to have a
gcc/glibc API to actually set the base addr of a VLA dynamically assuming
the user knows what she is doing?

WIthout an API, at the compiler level accepting a cast like (int[*][*])
could do the job, basically it would be identical to int* but would make
the cast possible removing the need for base addr patch and the dummy array
x[1][1] in my example the code would become



void worker(int tndx, long n, long m, int a[n][m])               /* (*6) */
{
#if 0 //hack removed
  long *np=&n, *mp=&m, i=mp-np, *ap=mp+i;                        /* (*7) */

  *ap=(long)ga;
#endif
  /* 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], hack removed */ tndx = (int)(long)v;
       /* (*4) */
  printf("thread #%d started\n", tndx);
  worker(tndx, (long)gn, (long)gm, (int[*][*])ga);   <=== ideal cast
}

Thanx in advance for your suggestions or comment in the future possible
extensions?

Cheers,
Phi



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux