Препроцессор макросов командной строки С++ не может заменить слово

Я работаю в среде командной строки терминала Linux, без IDE. Я компилирую свои программы на С++ с помощью g++. Это зависит от использования макросов командной строки для выполнения различных операторов кода без изменения самого исходного кода. Вот кусок кода, где у меня есть проблема. У меня есть несколько разных массивов, по которым я хочу выполнить сортировку. Затем у меня есть функции где-то еще в исходном коде, которые выполняют эту сортировку и возвращают отсортированный массив. Я хочу использовать макросы командной строки, чтобы сообщить препроцессору, какой массив я хочу использовать, и какой алгоритм сортировки использовать (какую функцию вызывать). SORT_ALG следует заменить на имя функции, а ARRAY — на имя массива. Таким образом, после предварительной обработки строка должна выглядеть так:

int* sorted_array = BubbleSort(array1, array1_size);

Вот исходный код:

  int array1[] = {24, 13, 9, 64, 7, 23, 34, 47};
  int array1_size = sizeof(array1) / sizeof(array1[0]);

  // an already sorted array!
  int array2[] = {1, 2, 5, 8, 10, 15, 20, 25, 30};
  int array2_size = sizeof(array2) / sizeof(array2[0]);

  // a reverse sorted array!
  int array3[] = {75, 50, 45, 30, 25, 18, 17, 12, 10, 6, 5}; 
  int array3_size = sizeof(array3) / sizeof(array3[0]);

  /*  
   * This code uses command line macros defined by g++
   * SORT_ALG should be one of the sorting function names such as:
   *   BubbleSort
   *   BubbleSortOptimized
   * ARRAY should be the name of one of the arrays, without the brackets:
   *   array1
   *   array2
   *   array3
   * Example of compiling the program with g++ using command line macros:
   *   g++ -D SORT_ALG=BubbleSort -D ARRAY=array1 sorting.cpp
   */
  int* sorted_array = SORT_ALG(ARRAY, ARRAY_size);
  cout << "The sorted array: ";
  PrintArray(sorted_array, ARRAY_size);
  cout << endl;

Когда я пытаюсь скомпилировать исходный код, препроцессор не распознает замену ARRAY_size соответствующей переменной: array1_size.

 $ g++ -D SORT_ALG=BubbleSort -D ARRAY=array1 sorting.cpp
sorting.cpp: In function ‘int main()’:
sorting.cpp:139:39: error: ‘ARRAY_size’ was not declared in this scope
   int* sorted_array = SORT_ALG(ARRAY, ARRAY_size);

Я думаю, что препроцессор должен распознать ARRAY как array1, а затем заменить ARRAY_size на array1_size. Я думаю, что было бы хорошо не определять другой макрос командной строки для указания размера массива, потому что мне пришлось бы подсчитывать количество элементов, и я собираюсь использовать это в ситуациях, когда я не могу заранее знать размер массива. Поэтому у меня компилятор определяет размер массива. Является ли подчеркивание причиной того, что препроцессор не справляется со своей работой? Лучше использовать другое соглашение об именах для размера массива, чтобы он правильно препроцессировался? Какой другой подход вы бы предложили для решения этой проблемы?


person Galaxy    schedule 02.04.2017    source источник
comment
Это не ARRAY, это ARRAY_size. Хорошо, что препроцессор не заменяет часть идентификатора. Только представьте, из всех макросов наверняка есть один, идентификатор которого содержится в одном из ваших.   -  person chris    schedule 03.04.2017
comment
Это то, что я хочу, чтобы препроцессор делал, заменял часть идентификатора. Как препроцессор узнает, когда заканчивается идентификатор? Он разделен пробелами?   -  person Galaxy    schedule 03.04.2017
comment
Да, любым символом, который не может продолжать идентификатор.   -  person chris    schedule 03.04.2017
comment
А если я хочу назвать array1_size размером массива? Это означает, что обе переменные напрямую связаны ... как мне заставить препроцессор безупречно заменить их обе, используя один макрос командной строки?   -  person Galaxy    schedule 03.04.2017
comment
Вам удобно с #ifdef блоками?   -  person Beta    schedule 03.04.2017
comment
Вы используете C++, поэтому вместо этого используйте правильные контейнеры. Замените ваши литералы массива на std::array или std::vector или что-то в этом роде и используйте вместо этого array.size().   -  person Taywee    schedule 03.04.2017


Ответы (1)


С точки зрения препроцессора нельзя определить макрос FOO как BAR и ожидать, что FOO_size станет BAR_size, потому что FOO и FOO_size — разные токены.

Однако вы можете создать макрос вставки для этого:

#define GLUE(a,b) GLUEI(a,b)
#define GLUEI(a,b) a##b
...
int* sorted_array = SORT_ALG(ARRAY, GLUE(ARRAY,_size));

Макрос должен идти в паре с косвенным макросом, чтобы его аргументы могли расширяться. Из-за правил расширения макроса ARRAY в макросе будет расширяться первым (с учетом косвенности), что означает, что если вы определите его как что-то еще, что будет применяться перед вставкой.

Но с точки зрения препроцессора, почему вы все равно утруждаете себя использованием совпадающих парных токенов? Если array1_size будет назначено только sizeof(array1) / sizeof(array1[0]), вы можете просто изменить это на SORT_ALG(ARRAY, (sizeof(ARRAY)/sizeof(ARRAY[0]))).

(Кроме того, что именно вы здесь делаете? Похоже, на C++ может быть гораздо лучшая реализация, если вы делаете что-то более сложное, чем бенчмаркинг чего-то конкретного; и я озадачен, почему вы используете командную строку для переключения между алгоритмами).

person H Walters    schedule 02.04.2017
comment
Я согласен с вашим вторым предложением. Это кажется лучшим решением. - person Galaxy; 03.04.2017