Как построить гибкую иерархию кода
Итак, у меня есть алгоритм, состоящий из параметров A, B, C и D и операций X, Y и Z. Цель состоит в том, чтобы написать код, который будет проверять все комбинации (в пределах определенного диапазона) A, B, C и D, и, возможно, изменить операции X, Y или Z.
Это было бы просто, если бы это было просто вопросом размещения переменных в определенном диапазоне. Но так как я хочу также менять операторов, это не так просто.
Моя идея - написать код, который бы охватывал все комбинации. Например, давайте рассмотрим, что есть только два параметра (A и B) и что диапазон одинаков для обоих: [1,2], целые числа. Код будет создавать (и, если возможно, выполнять) 4 различных исполняемых файла, соответствующих использованию алгоритма с:
A = 1, B = 1
A = 1, B = 2
A = 2, B = 1
A = 2, B = 2
Теперь добавляем операторов. Например, мы выбираем предыдущий пример и добавляем операцию X, где это может быть [+,-]. Результирующий набор:
A = 1, B = 1, X = +
A = 1, B = 2, X = -
A = 2, B = 1, X = +
A = 2, B = 2, X = -
A = 1, B = 1, X = -
A = 1, B = 2, X = +
A = 2, B = 1, X = -
A = 2, B = 2, X = +
(Надеюсь, я написал все комбинации)
В любом случае, я полагаю, что такую структуру можно построить с помощью make-файла, в котором он приписывает значения константам кода, написанного на C. Я не уверен, что можно изменить операторы таким образом. Я думал об использовании make-файла для простоты. Всегда можно написать код, который генерирует код, но в данном случае выглядит довольно преувеличенным.
Возможно, это создаст древовидную структуру? Я не уверен, полезно ли это иметь (и выбираю первый пример):
|--Makefile
|--A1
| |--B1
| | |--a.out
| |--B2
| |--a.out
|--A2
|--B1
| |--a.out
|--B2
|--a.out
С помощью make я считаю, что могу добавить в код дополнительные переменные / операторы и легко перестроить все тесты. Кроме того, позволяет ли эта структура использовать функциональность заданий make для запуска нескольких потоков?
Спасибо
1 ответ
Метод, который я использовал в прошлом:
Вы можете написать сценарий оболочки для определения макроса и затем скомпилировать программу. Используя этот метод, вы можете написать только один исходный файл и скомпилировать несколько программ. Пример программы, которая выполняет некоторую операцию над двумя числами, переданными через аргументы командной строки:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv[]){
if (argc != 3){ //takes just 2 numbers (for example purposes)
fprintf(stderr, "Usage: prog num1 num2\n");
return 1;
}
int a = (int)strtol(argv[1], (char**)NULL, 10);
int b = (int)strtol(argv[2], (char**)NULL, 10);
int c = a MySpecialOperation b;
printf("%d %s %d = %d\n", a, MySpecialOperationText, b, c);
return 0;
}
Вы быстро заметите, что MySpecialOperation
а также MySpecialOperationText
не определены. Это намеренно. (Также программа предполагает, что аргументы командной строки действительны.)
Теперь предположим, что вы хотите 4 программы, которые выполняют 4 основных арифметических действия. Напишите скрипт для компиляции вашей программы (это в BASh):
echo \#define MySpecialOperation \+ > tmp.c
echo \#define MySpecialOperationText \"plus\" >> tmp.c
cat myprogram.c >> tmp.c
gcc tmp.c -o addition_prog
echo \#define MySpecialOperation \- > tmp.c
echo \#define MySpecialOperationText \"minus\" >> tmp.c
cat myprogram.c >> tmp.c
gcc tmp.c -o subtraction_prog
echo \#define MySpecialOperation \* > tmp.c
echo \#define MySpecialOperationText \"times\" >> tmp.c
cat myprogram.c >> tmp.c
gcc tmp.c -o multiplication_prog
echo \#define MySpecialOperation \/ > tmp.c
echo \#define MySpecialOperationText \"divided by\" >> tmp.c
cat myprogram.c >> tmp.c
gcc tmp.c -o division_prog
rm tmp.c
Этот скрипт автоматически создает новый файл, записывает оператор препроцессора #define
к нему, определяя ранее неопределенные переменные, затем добавляет исходный файл к нему. Теперь компилятор заменит MySpecialOperation
с операцией (+
,-
,*
, или же /
) а также MySpecialOperationText
с соответствующим словом, и код скомпилирует и выполнит эту операцию.