Ядро Linux использует хорошую реализацию ARRAY_SIZE
для решения этой проблемы:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
с
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
и
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
Конечно, это переносимо только в GNU C, так как он использует две instrinsics: typeof
operator и __builtin_types_compatible_p
. Кроме того, он использует свой «знаменитый» макрос BUILD_BUG_ON_ZERO
, который действителен только в GNU C.
Предполагая требование оценки времени компиляции (это то, что мы хотим), я не знаю никакой переносимой реализации этого макрос.
Реализация «полу-портативная» (и которая не охватывает все случаи):
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
с
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
С помощью gcc
это не дает предупреждения, если аргумент является массивом в -std=c99 -Wall
, но -pedantic
выдаст предупреждение. Причина в том, что выражение IS_ARRAY
не является целочисленным константным выражением (приведение типов указателей и оператора индексирования не допускается в целых константных выражениях), а ширина битового поля в STATIC_EXP
требует целочисленного постоянного выражения.
Оказывается, Карабинер захватывал контроль над вводом и сбрасывал ключ home, который по иронии судьбы я установил, пытаясь переназначить ключ home, чтобы сбежать. Удаление его решило проблему.