2

I'd like to create dynamically a const char at compilation time as follow:

const char reprx[] = "repr1\0repr2\0repr3\0repr4\0";

and with a #define to specify the number of time the string reprX\0 is repeated within the string (by replacing X with a increment value). For example for 5:

const char reprx[] = "repr1\0repr2\0repr3\0repr4\0repr5\0";

Is there a simple way to do that? (without extra libraries)

Darko P.
  • 567
  • 1
  • 4
  • 14
  • What , with `#define` you wan to specify that ? its unclear . – ameyCU Sep 23 '15 at 15:30
  • There's no *simple* way. You can use the [Boost preprocessing macro library](http://www.boost.org/doc/libs/1_59_0/libs/preprocessor/doc/) but I suppose that counts as "extra libraries" – rici Sep 23 '15 at 15:30
  • Dunno if this counts as an "extra" libary but m4 might do the job: http://www.gnu.org/software/m4/m4.html – cadaniluk Sep 23 '15 at 15:33
  • @ameyCU the #define for the number of repetition. Yes I'd like to know first if it's possible without extra libraries. – Darko P. Sep 23 '15 at 15:39

2 Answers2

3

This can give you a clue:

#include <stdio.h>

#define repeat1(s) s"1\0"
#define repeat2(s) repeat1(s)s"2\0" 
#define repeat3(s) repeat2(s)s"3\0" 
#define repeat4(s) repeat3(s)s"4\0" 
#define repeat5(s) repeat4(s)s"5\0"
#define repeat6(s) repeat5(s)s"6\0" 
#define repeat7(s) repeat6(s)s"7\0" 
#define repeat8(s) repeat7(s)s"8\0" 
#define repeat9(s) repeat8(s)s"9\0" 

#define repeat(s, n) repeat##n(s)

int main(void)
{
    printf("%s\n", repeat("repr", 5));
    return 0;
}

Output:

printf("%s\n", "repr""1\0""repr""2\0""repr""3\0""repr""4\0""repr""5\0");

Note that this version is limited to 9 strings.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • 1
    This is the simplest way. However I had to remove ## on each repeat otherwise I've the error: does not give a valid preprocessing token. (don't know why) Furthermore, in order to use a #define instead of the numerical value, I defined the helper: #define REPEAT_HELPER(s, n) REPEAT##n(s) #define REPEAT(s, n) REPEAT_HELPER(s, n). I'd have liked to not to write explicitly the nested repeat but its seems that without extra libraries we couldn't do otherwise. – Darko P. Sep 23 '15 at 16:22
1

The simplest way to do this would be to use a custom preprocessing script, which you could integrate into your build process.

I don't know what tools you have available, but you could easily use awk as a preprocessor. If you're using make, you could build the c file automatically from a skeleton: (See below for the original awk script.)

file.c: file.c.in
        awk '                                          \
        /^#define X / {                                \
           for (i = 1; i <= $$3; ++i)                  \
             s = s "\"repr"i"\\0\""                    \
           }                                           \
        match($$0, / *const char \*reprx\[\] = /)  {   \
           $$0 = substr($$0, 1, RLENGTH) s ";"         \
        }                                              \
        1' $^ > $@

Example:

$ cat file.c.in
/* The beginning of the program */
#define X 7
/* Some part of the program */
const char *reprx[] = "Will be replaced";
/* The rest of the program */

$ make -s file.c
$ cat file.c
/* The beginning of the program */
#define X 7
/* Some part of the program */
const char *reprx[] = "repr1\0""repr2\0""repr3\0""repr4\0""repr5\0""repr6\0""repr7\0";
/* The rest of the program */

Since it is a little obscured by the need to escape dollar signs and line endings, here's the original awk program:

awk '/^#define X / {
        for (i = 1; i <= $3; ++i)
            s = s "\"repr"i"\\0\""
        }
     match($0, / *const char \*reprx\[\] = /)  {
        $0 = substr($0, 1, RLENGTH) s ";"
     }
     1'
rici
  • 234,347
  • 28
  • 237
  • 341
  • Thanks for this more elaborated way. Its interesting I didn't know awk. But it requires more knowledge and its not what I'm looking for ;) – Darko P. Sep 23 '15 at 16:26
  • @dark0: It doesn't have to be awk, but awk is a tool almost always present, even on embedded systems. It helps to have `make` when you're using external preprocessing scripts; again, there is almost always some kind of make tool, and a preprocessing step is usually not complicated to add to a build configuration. The advantage of external preprocessors is that you don't have to fight with the peculiarities of the C preprocessor -- for example, you can do loops and perform arithmetic in a straightforward way -- and they don't have limitations like "no more than 9" (or 256 with boostpp). – rici Sep 23 '15 at 17:39
  • You're right. This seems the most efficient way to do that. I don't know actually how to implement that since the make files are generated automatically by the IDE. But I take note of your solution and guess that I'm gonna use it one day if not immediately. – Darko P. Sep 24 '15 at 08:06