Есть и другие способы, но вы, вероятно, не хотите их использовать. То, что вы делаете, это хорошее использование препроцессора. Хотя я бы написал что-то вроде:
#ifndef MAX_SIZE
#define MAX_SIZE 42
#endif
constexpr size_t maxSize = MAX_SIZE;
Таким образом, фактическая часть кода, тип переменной, имя и т. Д. c. Должны быть записаны только один раз. Также учтите:
#indef MAX_SIZE
#error "You need to define MAX_SIZE to compile this code, e.g. -DMAX_SIZE=42"
#endif
Таким образом, кто-то не использует значение по умолчанию, когда он этого не хочет, потому что он не знает, как его определить, или что-то в системе сборки сделало флаг -D заблудиться где-нибудь.
Но есть и другие способы, и можно избежать макросов препроцессора!
Генерация самого исходного кода. Хотя это может показаться сложным и часто таковым, существуют способы сделать его менее сложным. Структурируйте код так, чтобы часть, которая должна быть сгенерирована, была маленькой. Например, получить другие значения из одного определения maxSize
вместо генерации всего кода, который должен знать размер. Есть также системы, которые уже могут делать это в некоторых случаях. Например, если кто-то использует CMake, создайте файл header.h.in следующим образом:
constexpr size_t maxSize = @MAXSIZE@;
, а затем поместите его в файл CMakeLists.txt:
set(MAXSIZE 42)
configure_file(header.h.in header.h @ONLY ESCAPE_QUOTES)
Когда проект построен, cmake превратит header.h.in в header.h с @MAXSIZE@
, измененным на 42. При этом не использовался препроцессор C ++ , но мы эффективно использовали CMake препроцессор для предварительной обработки файла перед его компиляцией, так что же, он отличается? Это просто другой язык препроцессора (который не так хорош, как язык препроцессора C / C ++).
Другой способ - с использованием констант времени соединения. Символ компоновщика обычно является именем функции или глобальной переменной. Что-то со стати c срок хранения. Значением символа является адрес объекта. Но в командах компоновщику можно определить любой символ, который вы хотите. Вот пример C file:
#include <stdio.h>
char array1[1];
extern array2[];
int main(void) { printf("%p %p\n", array1, array2); return 0; }
Скомпилируйте с g cc как gcc example.c -Wl,--defsym=array2=0xf00d
.
Так же, как он печатает адрес array1, он напечатает 0xf00d
как адрес array2
. И поэтому мы ввели константу в наш код без использования какого-либо препроцессора, ни C, ни CMake.
Но это значение не известно компилятору, только компоновщику. Это не «целочисленное константное выражение», и его нельзя использовать в определенных местах, таких как метки регистра или размер объекта с длительностью хранения stati c. Потому что компилятор должен знать точное значение тех, которые компилируют код. Компилятор сгенерировал код для вызова printf, не зная точного значения array1
или array2
. Это не могло сделать это для метки выписки. Это действительно так, хотя «целочисленные константные выражения» существуют в стандартах C / C ++ и не совпадают с выражениями, которые являются константными и имеют целочисленный тип.