1

I have a question. In my own webserver I have the following code at the file scope:

typedef struct {
    char *slice;
    int length;
} values_index;

const char *aHeaderKeys[] = {
    /* You can add here whatever you want! */
    "Accept",
    "Accept-Charset",
    "Accept-Encoding",
    "Accept-Language",
    "Authorization",
    "Expect",
    "From",
    "Host",
    "If-Match",
    "If-Modified-Since",
    "If-None-Match",
    "If-Range",
    "If-Unmodified-Since",
    "Max-Forwards",
    "Proxy-Authorization",
    "Range",
    "Referer",
    "TE",
    "User-Agent",
    "Connection"
};

int nHeadersSizes[sizeof(aHeaderKeys) / sizeof(*aHeaderKeys)];
values_index aHeaderValuesIndexes[sizeof(aHeaderKeys) / sizeof(*aHeaderKeys)];
const int nHeadersLen = sizeof(aHeaderKeys) / sizeof(*aHeaderKeys);

But, since aHeaderKeys is an array of a constant length of constant strings, it's stupid to calculate the length of the array during the execution of the program and it should be better to write it manually:

typedef struct {
    char *slice;
    int length;
} values_index;

const char *aHeaderKeys[20] = {
    /* You can add here whatever you want! */
    "Accept",
    "Accept-Charset",
    "Accept-Encoding",
    "Accept-Language",
    "Authorization",
    "Expect",
    "From",
    "Host",
    "If-Match",
    "If-Modified-Since",
    "If-None-Match",
    "If-Range",
    "If-Unmodified-Since",
    "Max-Forwards",
    "Proxy-Authorization",
    "Range",
    "Referer",
    "TE",
    "User-Agent",
    "Connection"
};

int nHeadersSizes[20];
values_index aHeaderValuesIndexes[20];
const int nHeadersLen = 20;

But the number of the elements of my array can change during the developing process, so every time I want to add another element I have to change manually the length everywhere. Now my question is: is it possible to write a preprocessor macro like the following one I wrote in JavaScript (as pseudocode)?

var aHeaders = [
    "Accept",
    "Accept-Charset",
    "Accept-Encoding",
    "Accept-Language",
    "Authorization",
    "Expect",
    "From",
    "Host",
    "If-Match",
    "If-Modified-Since",
    "If-None-Match",
    "If-Range",
    "If-Unmodified-Since",
    "Max-Forwards",
    "Proxy-Authorization",
    "Range",
    "Referer",
    "TE",
    "User-Agent",
    "Connection"
];

var sExplodedText = "const char *aHeaderKeys[" + aHeaders.length + "] = {\n\t\/* You can add here whatever you want! *\/\n\t\"" + aHeaders.join("\",\n\t\"") + "\"\n};\n\nint nHeadersSizes[" + aHeaders.length + "];\nvalues_index aHeaderValuesIndexes[" + aHeaders.length + "];\nconst int nHeadersLen = " + aHeaders.length + ";";

alert(sExplodedText);
grufo
  • 51
  • 6

2 Answers2

3

No need to specify the size of the array, the compiler figures it out. You can just do

const char *aHeaderKeys[] = {
...
};


#define NR_HEADERS (sizeof aHeaderKeys/sizeof aHeaderKeys[0])

Then use NR_HEADERS wherever you need. The expression here will be calculated by the compiler at compile time, there's no runtime calculation going on.

nos
  • 223,662
  • 58
  • 417
  • 506
  • Or: `enum { NUM_HEADER_KEYS = sizeof(aHeaderKeys) / sizeof(aHeaderKeys[0]) };` which places the chosen name in the symbol table, rather than losing it when the preprocessor is run, making debugging easier. – Jonathan Leffler Dec 01 '13 at 15:20
  • @nos Wow, thank you! So, are you sure that "The expression here will be calculated by the compiler at compile time"? Really do you mean that the precompiler will explode NR_HEADERS as "20" and not as "(sizeof aHeaderKeys/sizeof aHeaderKeys[0])"? How is it possible?? – grufo Dec 01 '13 at 15:30
  • The compiler, not the preprocessor, will evaluate this at compile time. The sizeof here is constant, and the division is carried out at compile time too. Yes I am sure. – nos Dec 01 '13 at 15:49
  • @nos So, it is not useful to add to the file scope: const int nHeadersLen = NR_HEADERS; I can use sizeof(aHeaderKeys) / sizeof(aHeaderKeys[0]) even within functions scope and it will replaced at compile time with 20… Is it right? – grufo Dec 01 '13 at 15:58
0

So, thanks to @nos and @JonasWielicki, here is the solution.

It is sure that NR_HEADERS in the following line

#define NR_HEADERS (sizeof aHeaderKeys / sizeof *aHeaderKeys)

will be always replaced with 20 at compile time and there will be no runtime calculation going on in the following code:

const char *aHeaderKeys[] = {
    /* You can add here whatever you want! */
    "Accept",
    "Accept-Charset",
    "Accept-Encoding",
    "Accept-Language",
    "Authorization",
    "Expect",
    "From",
    "Host",
    "If-Match",
    "If-Modified-Since",
    "If-None-Match",
    "If-Range",
    "If-Unmodified-Since",
    "Max-Forwards",
    "Proxy-Authorization",
    "Range",
    "Referer",
    "TE",
    "User-Agent",
    "Connection"
};

#define NR_HEADERS (sizeof aHeaderKeys/sizeof sizeof *aHeaderKeys)

values_index aHeaderValuesIndexes[NR_HEADERS];
int nHeadersSizes[NR_HEADERS];

So, problem solved!

Thank you!

grufo
  • 51
  • 6