1

Is there a way to determine a position within a const array at compile-time in c? Here's an example of what I'm trying to do:

const unsigned char DATA[] = {
// Part 1 
// hundreds or thousands of values

// Part 2  
// compiler records this position in the array in PART2
// hundreds or thousands of values

// Part 3  
// compiler records this position in the array in PART3
// hundreds or thousands of values

// ...
};

const unsigned int PART_IDX [] = {
// index to Part 1
0,

// index to Part 2
PART2,

// index to Part 3
PART3,

// ...
};

I could calculate the indexes at run-time, but would rather have them already done, since the array is constant. I could make a program that analyzes the source code, counts the number of elements in each part, and inserts the data in PART_IDX, but I would really like to have the compiler do this at compile-time. That way if data gets inserted or deleted, or parts get added or removed, the compiler still generates correct code. Does someone know how I could do this? Thanks!

Edit: To clarify, using a example with actual data:

const unsigned char DATA[] = {
// Part 1 
0, 1, 2, 3, 4,

// Part 2  
// compiler records this position in the array in PART2 (should be 5)
10, 11, 12, 13, 14, 15, 16,

// Part 3  
// compiler records this position in the array in PART3 (should be 12)
20, 21, 22
};

const unsigned int PART_IDX [] = {
// index to Part 1
0,

// index to Part 2
PART2,   // should be 5, points to 10 in the array

// index to Part 3
PART3,   // should be 12, points to 20 in the array
};

Question is, what can I put in place of the lines that start with // compiler records this position ... to get the compiler to record the appropriate values in PART2 and PART3?

Robert
  • 13
  • 4
  • 2
    It's not clear on what information you expect this index calculation to be made. What constitutes a "part" of your array? – François Andrieux Oct 09 '19 at 18:27
  • 3
    Do you need this for C or for C++? Can't you make the three parts separate arrays? – M Oehm Oct 09 '19 at 18:28
  • Is the compiler obligated to provide compile-time access to this information? – tadman Oct 09 '19 at 18:33
  • 1
    Can you give an example of what you want the code to look like with a smaller number of elements, say 5 -10? – dbush Oct 09 '19 at 18:34
  • @FrançoisAndrieux: The basis for the calculations will be some thing marked or recorded by lines inserted in the list of initializers, like `MarkerMacro(Part2)`. E.g., using slashes to mark the lines, the array might be initialized with `{ / MarkerMacro(Part1) / 3, 4, 5, / MarkerMacro(Part2) / 6, 7, 8, 9, / MarkerMacro(Part3) / 10, 11, }`. – Eric Postpischil Oct 09 '19 at 18:56
  • What constitutes a part? That's where I have the comment `// hundreds or thousands of values` you could replace that with something like `0x57, 0xf3, 0x4a, 0x77, ...`. The idea is for the compiler to count them and tell me where the next part starts. – Robert Oct 09 '19 at 18:59
  • I want the parts to be in the same array as the same code will be processing the parts. Won't necessarily be just three parts, may be many parts. Would also like to add or remove parts and have the compiler do all the calculations. – Robert Oct 09 '19 at 19:01
  • @EricPostpischil: looks kinda like what I want to do. How do I get values from MarkerMacro to use in PART_IDX? – Robert Oct 09 '19 at 19:09

2 Answers2

3

Rather than trying to kludge C to do something it was not meant to do, a better and common method is to prepare data for a C program by writing a program that prepares the data. That is, write some other program that counts the data in the parts and writes the C code necessary to initialize both DATA and PART_IDX.

Another option is:

  • Put all the data each part in a separate “.h” file, such as files “part1.h”, “part2.h”, “part3.h”.
  • To initialize DATA, include all of those header files in its initializer list.
  • To calculate the indices for the parts, use sizeof to calculate the numbers of elements in proxy arrays containing the preceding parts.

Example:

“part1.h” contains 10, 11, 12,.

“part2.h“ contains 20, 21,.

“part3.h” contains 30, 31, 32, 33,.

The C file is:

const unsigned char DATA[] =
{
    #include "part1.h"
    #include "part2.h"
    #include "part3.h"
};


const unsigned int PART_IDX [] =
{
    0,

    sizeof (const unsigned char []) {
        #include "part1.h"
    } / sizeof (const unsigned char),

    sizeof (const unsigned char []) {
        #include "part1.h"
        #include "part2.h"
    } / sizeof (const unsigned char),
};


#include <stdio.h>


int main(void)
{
    for (int i = 0; i < 3; ++i)
        printf("Part %d begins at index %d with value %d.\n",
            i, PART_IDX[i], DATA[PART_IDX[i]]);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Interesting technique. Didn't realize you could use `sizeof` that way. Works with using `#define` to specify array portions that then get combined into a single array as well. Instead of include files that you then `#include` you can use `#define` to create defined constants with the parts and then use the defined constants in places where you are doing the `#include`. Not that I'm suggesting defined constants as there is a limit on the length of those but for smaller data sets it could work well. – Richard Chambers Oct 09 '19 at 20:18
  • That worked great! An added benefit is that each part is contained in its own file. I can reorder them, or add and delete them much easier. Thanks! – Robert Oct 09 '19 at 20:42
1

Is there a way to determine a position within a const array at compile-time in c?

Yes. Remember that C source files can be generated, and improve your build automation accordingly (e.g. edit your Makefile).

So just generate the second part (e.g. with some awk or Guile script on Linux, or your own simple meta-program coded in C -or some scripting language- that output portions of generated C code). Play with preprocessor tricks. See this answer for inspiration.

You could, assuming you use GCC as your C compiler, also consider writing your ad-hoc GCC plugin, but in your particular case it is not worth the effort.

BTW, my Bismon program uses such meta-programming tricks. And GCC itself has dozens of ad-hoc code generators.

If you generate some complex enough C code, I recommend keeping internally some kind of AST of it.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547