Компилятор ccblkfn определяет макросы, предоставляющие информацию о компиляторе, исходном файле и указанных опциях командной строки (predefined macros). Эти макросы могут проверяться с помощью директивы #ifdef и других подобных, чтобы управлять процессом компиляции программы. Что-то подобное делается определением макросов в системных заголовочных файлах.
Примечание: кроме предопределенных макросов, также есть предопределенные утверждения (Predefined Assertions), см. врезку ниже.
Опция командной строки -A name (токены) указывает компилятору утвердить (assert) имя в качестве предиката с заданными токенами. Это дает тот же эффект, как директива препроцессора #assert. Заранее определенные утверждения (predefined assertions) перечислены в таблице 1-8.
Таблица 1-8. Predefined Assertions.
Assertion
Значение
system
embedded
machine
adspblkfn
cpu
adspblkfn
compiler
ccblkfn
Опция -A name (value) эквивалентна включению в компилируемый исходный код директивы:
#assert name(value)
После этого утвержденные имена могут быть проверены препроцессором:
#if #name(value)// какие-то действия
...
#else // какие-то другие действия
...
#endif
Например, утверждения по умолчанию могут быть проверены следующим образом:
#if #machine(adspblkfn)// какие-то действия
...
#endif
Примечание: когда используется опция -A, для круглых скобок в утверждении нужно применять кавычки, чтобы предотвратить неправильную интерпретацию опции -A. В директиве #assert исходного файла кавычки не нужны.
Макросы, такие как __DATE__, могут быть полезны при встраивании в текстовые строки. Оператор # в теле макроса полезен для преобразования таких символов в текстовые конструкции.
В таблице 1-41 описываются предопределенные макросы, которые создает компилятор ccblkfn. Многие опции зависят от опций командной строки компилятора, см. [2].
Таблица 1-41. Predefined Compiler Macros.
Макрос
Функция
_ADI_FX_LIBIO
Определен как 1, когда компилируется с опцией -fixed-point-io.
_ADI_COMPILER
Определен как 1.
__ADSPBF50x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF504, ADSP-BF504F или ADSP-BF506F.
__ADSPBF51x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF512, ADSP-BF514, ADSP-BF516 или ADSP-BF518.
__ADSPBF52x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF522, ADSP-BF524, ADSP-BF526, ADSP-BF523, ADSP-BF525 или ADSP-BF527.
__ADSPBF52xLP__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF522, ADSP-BF524, ADSP-BF526, ADSP-BF523, ADSP-BF525 или ADSP-BF527.
__ADSPBF52xLP__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF522, ADSP-BF524 или ADSP-BF526.
__ADSPBF53x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF531, ADSP-BF532, ADSP-BF533, ADSP-BF534, ADSP-BF536, ADSP-BF537, ADSP-BF538 или ADSP-BF539. Примечание: это не включает процессор ADSP-BF535 processor.
__ADSPBF54x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF542, ADSP-BF544, ADSP-BF547, ADSP-BF548 или ADSP-BF549.
__ADSPBF56x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF561.
__ADSPBF59x__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF592-A.
__ADSPBLACKFIN__
Всегда определен как 1.
__ADSPLPBLACKFIN__
Определен как 1, когда целевой процессор (установленный опцией -proc) относится к мало потребляющим (low-power core). Это включает процессоры ADSP-BF504, ADSP-BF504F, ADSP-BF506F, ADSP-BF512, ADSP-BF514, ADSP-BF516, ADSP-BF518, ADSP-BF522, ADSP-BF523, ADSP-BF524, ADSP-BF525, ADSP-BF526, ADSP-BF527, ADSP-BF531, ADSP-BF532, ADSP-BF533, ADSP-BF534, ADSP-BF536, ADSP-BF537, ADSP-BF538, ADSP-BF539, ADSP-BF542, ADSP-BF547, ADSP-BF548, ADSP-BF549, ADSP-BF561 или ADSP-BF592-A.
__ADSPBF506F_FAMILY__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF504, ADSP-BF504F или ADSP-BF506F.
__ADSPBF518_FAMILY__
Эквивалент __ADSPBF51x__.
__ADSPBF526_FAMILY__
Эквивалент __ADSPBF52xLP__.
__ADSPBF527_FAMILY__
Эквивалент __ADSPBF52x__.
__ADSPBF533_FAMILY__
Эквивалент __ADSPBF53x__.
__ADSPBF535_FAMILY__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF535.
__ADSPBF537_FAMILY__
Эквивалент __ADSPBF53x__.
__ADSPBF538_FAMILY__
Эквивалент __ADSPBF53x__.
__ADSPBF548_FAMILY__
Эквивалент __ADSPBF54x__.
__ADSPBF548M_FAMILY__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF542M, ADSP-BF544M, ADSP-BF547M, ADSP-BF548M или ADSP-BF549M.
__ADSPBF592_FAMILY__
Определен как 1, когда целевой процессор (установленный опцией -proc) ADSP-BF592-A.
__ANALOG_EXTENSIONS__
Определен как 1. Если разрешена проверка совместимости MISRA, то этот макрос не определен.
__cplusplus
Определен как 199711L, когда код компилируется в режиме C++.
__DATE__
Препроцессор разворачивает этот макрос в строковую константу, в которой находится дата. Строка даты имеет формат mm dd yyyy (стандарт ANSI).
__DOUBLES_ARE_FLOATS__
Определен как 1, когда размер типа double такой же, как у типа float обычной точности (single-precision float type). Когда используется опция командной строки компилятора -double-size-64, этот макрос не определен.
__ECC__
Всегда определен как 1.
__EDG__
Всегда определен как 1. Это определение обозначает использование фронт-энда Edison Design Group.
__EDG_VERSION__
Всегда целочисленное значение, представляющее версию компилятора фронт-энда.
__EXCEPTIONS
Определен как 1, когда разрешена обработка исключений (exception handling) языка C++ (с использованием опции -eh).
__FILE__
Препроцессор разворачивает этот макрос в строковую константу, содержащую имя текущего входного файла. Эта строка совпадает с именем файла, указанного в командной строке или в команде препроцессора #include (стандарт ANSI).
_INSTRUMENTED_PROFILING
Определен как 1, когда разрешен инструментальный профайлинг (с помощью опции -p командной строки компилятора).
_LANGUAGE_C
Всегда определен как 1.
__LINE__
Препроцессор разворачивает этот макрос в десятичную целочисленную константу, представляющую номер текущей строки (стандарт ANSI).
_MISRA_RULES
Определен как 1, когда компиляция происходит в режиме MISRA-C.
__NO_BUILTIN
Определен как 1, когда компиляция происходит с использованием опции -no-builtin командной строки компилятора.
__NUM_CORES__
Определен в количество ядер выбранного целевого процессора. Например, когда компиляция происходит для процессора ADSP-BF533, __NUM_CORES__ определен как 1, а при компиляции для процессора ADSP-BF561 __NUM_CORES__ определен как 2.
__RTTI
Определен как 1, когда разрешена информация о типах времени выполнения C++ (run-time type information) с помощью опции командной строки компилятора -rtti.
__SIGNED_CHARS__
Определен как 1 за исключением случаев, когда компиляция происходит с опцией -unsigned-char.
__STDC__
Всегда определен как 1.
__STDC_VERSION__
Определен как 199409L, когда компиляция происходит в режиме C89, и как 199901L, когда компиляция происходит в режиме C99.
__TIME__
Препроцессор разворачивает этот макрос в строковую константу, содержащую текущее время. Формат этой строки hh:mm:ss (стандарт ANSI).
__VERSION__
Определен как строковая константа, содержащая номер версии компилятора, используемого для компиляции этого модуля.
__VERSIONNUM__
Определен как целочисленная константа __VERSION__, сконструированная из номера версии компилятора. Каждый компонент версии использует 8 бит, и самый значащий байт значения представляет самый значимый (первый) компонент номера версии. Например, компилятор версии 7.1.0.0 определит __VERSIONNUM__ как 0x07010000, и версии 7.1.1.10 определит __VERSIONNUM__ как 0x0701010A.
__VISUALDSPVERSION__
Препроцессор определяет этот макрос в шестнадцатеричное число из 8 цифр, обозначающее релиз VisualDSP++, в форме 0xMMmmuurr, где: – MM это major номер релиза, – mm minor номер релиза, – uu номер обновления, – rr это "00", зарезервировано для будущего использования.
Например, VisualDSP++ 5.0 Update 1 получит __VISUALDSPVERSION__ как 0x05000100.
__WORKAROUNDS_ENABLED
Определен как 1, если компилятором реализован любой способ обхода ошибки кристалла (hardware workaround). Этот макрос установлен, если у опции -si-revision применено значение, отличающееся от "none", или если выбран любой специфичный workaround с помощью опции -workaround.
[Написание макросов препроцессора]
#define имя блок_текста
Макрос это определенное пользователем имя или строка, вместо которой препроцессор подставляет определенный пользователем блок текста. Для создания макроса используется команда препроцессора #define препроцессора. Когда определение макроса имеет аргументы, препроцессор модифицирует создаваемый блок текста, подставляя аргументы макроса.
Составные макросы. Составным макросом (Compound Macro) называют макрос, который состоит из нескольких строк. Продолжение макроса в следующей строке обеспечивается обратным слешем (\) в конце строки. Составной макрос может работать так же, как встроенная (inline) функция.
#define имя строка1 \
строка2 \
строка3
Замечание: при любой возможности используйте inline-функции (встраиваемые функции) вместо составных макросов. Если все-таки составной макрос необходим, определяйте составной макрос так, чтобы его можно было использовать наподобие вызовов функции. Это делает исходный код проще для чтения и поддержки.
Ниже в качестве примера определены две версии составного макроса SKIP_SPACES.
Во втором варианте тело макроса обрамлено однопроходным циклом do {...} while (0), что превращает его в один оператор, когда он обработан препроцессором. Первый вариант, в отличие от второго варианта, препроцессор разворачивает в составной оператор. С макросом, который разворачивается в составной оператор, Вы иногда можете пропустить точку с запятой после вызова макроса, и компилятор ничего не заметит, получится допустимая программа. Это приводит к необходимости помнить, что конкретно используется - функция или макрос, и нужна ли для макроса завершающая точка с запятой, или нет. Конструкция с обрамлением do {...} while (0) лишена такого недостатка, макрос можно считать функцией, и завершать его вызов точкой с запятой.
Например:
/* SKIP_SPACES, закрытый макрос, заканчивается без ';' */
if (*p !=0)
SKIP_SPACES (p, lim);
else ...
Этот макрос развернется в следующий код:
if (*p !=0)
do {
...
} while (0);
else ...
Без конструкции do {...} while (0) преобразование макроса было бы таким:
if (*p !=0)
{
...
}; /* Скорее всего это совсем не то, что нужно было получить... */