Препроцессор C: динамический const char

Я хотел бы создать динамически const char во время компиляции следующим образом:

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

и с помощью #define указать количество раз, когда строка reprX\0 повторяется внутри строки (путем замены X на значение приращения). Например для 5:

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

Есть ли простой способ сделать это? (без дополнительных библиотек)

2 ответа

Решение

Это может дать вам подсказку:

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

Выход:

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

Обратите внимание, что эта версия ограничена 9 строками.

Простейший способ сделать это - использовать пользовательский сценарий предварительной обработки, который вы можете интегрировать в процесс сборки.

Я не знаю, какие инструменты у вас есть в наличии, но вы могли бы легко использовать awk в качестве препроцессора. Если вы используете makeВы могли бы построить c файл автоматически из скелета: (См. ниже для оригинального сценария awk.)

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' $^ > $@

Пример:

$ 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 */

Так как это немного затенено необходимостью избегать знаков доллара и концов строк, вот оригинальная программа awk:

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'
Другие вопросы по тегам