Как структурировать макросы, которые являются результатом операций над макросами? - PullRequest
6 голосов
/ 19 августа 2011

Вот программа, которая иллюстрирует мою проблему:

#include <stdio.h>

#define NUMERATOR 8
#define DENOMINATOR 2
#define QUOTIENT (NUMERATOR / DENOMINATOR)

#define ZSTR(x) XSTR(#x)
#define YSTR(x) XSTR(x)
#define XSTR(x) STR(x)
#define STR(x) #x

int main()
{
    printf("QUOTIENT:       %d\n", QUOTIENT);
    printf("STR(QUOTIENT):  %s\n", STR(QUOTIENT));
    printf("XSTR(QUOTIENT): %s\n", XSTR(QUOTIENT));
    printf("YSTR(QUOTIENT): %s\n", YSTR(QUOTIENT));
    printf("ZSTR(QUOTIENT): %s\n", ZSTR(QUOTIENT));
    return 0;
}

И вот его вывод:

$ gcc -g -Wall -o stringify stringify.c && ./stringify 
QUOTIENT:       4
STR(QUOTIENT):  QUOTIENT
XSTR(QUOTIENT): (8 / 2)
YSTR(QUOTIENT): (8 / 2)
ZSTR(QUOTIENT): "QUOTIENT"

Я хотел бы передать строковый литерал "4" компилятору, но я теряю надежду. Это связано с этим вопросом , но добавляет уровень.

Ответы [ 4 ]

4 голосов
/ 20 августа 2011

Вы можете определить макросы, которые вставляют вместе свои аргументы, а затем определить (большое) число других макросов, которые выполняют оценку как вид таблицы:

#define DIV(X, Y)  DIV_(X, Y)
#define DIV_(X, Y) DIV_##X##_##Y
#define DIV_0_1  0
#define DIV_1_1  1
#define DIV_2_1  2
    :
#define DIV_8_2  4
    :

Это довольно утомительно, ноВы можете легко написать небольшую программу для генерации заголовочного файла с указанным выше материалом и запустить его как часть процесса сборки.Тогда вам просто нужно

#define QUOTIENT  DIV(NUMERATOR, DENOMINATOR)

Обратите внимание, что его вещи работают только для целых чисел без знака - если вам нужны отрицательные числа или числа с плавающей запятой, они не будут работать

3 голосов
/ 20 августа 2011

С помощью некоторых приемов вы можете реализовать базовую арифметику в соответствующем препроцессоре C99. P99 реализует арифметику и логику для малых десятичных чисел. * Например 1005 *

P99_IF_GT(1,0)(true)(false)
P99_ADD(3, 7)
P99_MUL(7, 2)
P99_DIV(7, 2)

будет предварительно обработан до чего-то вроде

1
10
14
3

Эти макросы могут обрабатываться далее, подвергаться строковому форматированию и тому, что вам больше нравится.

P99_STRINGIFY(P99_PASTE2(XXX_, P99_ADD(3, 7)))

приводит к "XXX_10" в результате предварительной обработки.

2 голосов
/ 20 августа 2011

Ну, я немного неохотно признаюсь, что знаю один способ сделать эту работу.

Атакуйте его с другого направления. Вы хотите, чтобы ваш компилятор видел нечто подобное.

#define QUOTIENT 4
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

Как мы можем это сделать, не используя буквальное число "4" в определении QUOTIENT, поскольку макропроцессор нам не поможет? Используя дополнительный препроцессор. Напишите исходный файл, stringify.c.awk, вот так.

/* stringify.c.awk --  Source file for stringify.c  
   (Put build instructions here.)  
 */
#define QUOTIENT NUMERATOR/DENOMINATOR
#include <stdio.h>

int main(void)
{
  printf("QUOTIENT:       %d\n", QUOTIENT);
  return 0;
}

Запишите вторичный препроцессор в awk. Я сознательно использовал действительно строгое регулярное выражение. Я думаю, что это наиболее вероятное регулярное выражение, если в исходном файле есть изменения, и я думаю, что это обычно то, что вы хотите. (Я обычно хочу препятствовать косметическим изменениям в #define.)

# stringify.awk -- calculate and substitute the value for #define QUOTIENT.
BEGIN {
  NUMERATOR = 8;
  DENOMINATOR = 2;
}
{
  if ($0~/^#define QUOTIENT NUMERATOR\/DENOMINATOR$/) {
    sub(/NUMERATOR\/DENOMINATOR/, NUMERATOR/DENOMINATOR);
  } 
  print $0;
}

Теперь вы можете собрать stringify.c из файла stringify.c.awk.

$ awk -f stringify.awk stringify.c.awk > stringify.c
$ gcc -Wall -o stringify stringify.c
$ ./stringify
QUOTIENT:       4

Makefile и щедрые комментарии устраняют большую часть боли.

(m4 не поможет по тем же причинам, что препроцессор C не поможет.)

2 голосов
/ 19 августа 2011

Лучшее, что вы можете сделать, это stringify расширение макроса, которое сделано с вашими XSTR и YSTR примерами.Хотя он может компилироваться в 4 с оптимизацией, все процессоры pre смогут увидеть (8 / 2)

...