Например, я недавно сталкивался с этим в ядре Linux:
/ * Принудительная ошибка компиляции, если условие истинно * / #define BUILD_BUG_ON (условие) ((недействительно) sizeof (символ [1 - 2 * !! (условие)]))
Итак, в вашем коде, если у вас есть какая-то структура, которая должна иметь размер, скажем, кратный 8 байтам, возможно, из-за некоторых аппаратных ограничений, вы можете сделать следующее:
BUILD_BUG_ON ((sizeof (struct mystruct)% 8)! = 0);
и он не скомпилируется, если размер struct mystruct не кратен 8, а если он кратен 8, код времени выполнения вообще не генерируется.
Другой известный мне трюк из книги «Графические жемчужины», которая позволяет одному заголовочному файлу как объявлять, так и инициализировать переменные в одном модуле, тогда как в других модулях, использующих этот модуль, просто объявлять их как внешние.
#ifdef DEFINE_MYHEADER_GLOBALS #define GLOBAL #define INIT (x, y) (x) = (y) #else #define GLOBAL extern #define INIT (x, y) #endif GLOBAL int INIT (x, 0); GLOBAL int somefunc (int a, int b);
При этом код, который определяет x и somefunc:
#define DEFINE_MYHEADER_GLOBALS #include "the_above_header_file.h"
в то время как код, который просто использует x и somefunc (), делает:
#include "the_above_header_file.h"
Таким образом, вы получаете один заголовочный файл, который объявляет как экземпляры глобальных переменных, так и прототипы функций, где они необходимы, и соответствующие объявления extern.
Итак, какие у вас любимые приемы программирования на С в этом направлении?
BUILD_BUG_ONмакросе, что не так с использованием #errorinside и #if?