Интересная проблема, с которой мы столкнулись на этой неделе.
Мы работаем в C на встроенной платформе Harvard Architecture, которая имеет 16-битные адреса данных и 32-разрядные коды.
Проблема возникает, когда вы работаете с указателями функций. Если у вас есть код типа
if (fp) fp();
или
if (fp != 0) fp();
все в порядке.
Однако, если у вас есть код типа
if (fp != NULL) fp();
тогда, поскольку NULL
определяется как (void *) 0
, компилятор (gcc в этом случае) a) не предупреждает и b) выполняет 16-битное сравнение с вашим указателем функции вместо 32-битного сравнения. До тех пор, пока ваш указатель функции не окажется на границе 64k, поэтому все нижние 16 бит равны 0.
В настоящий момент мы имеем большие фрагменты кода, которые содержат явные проверки против NULL. Большинство из них будут указателями данных, но некоторые из них будут указателями функций. Быстрый grep для != NULL
или == NULL
показал более 3000 результатов, для многих, чтобы пройти вручную, чтобы проверить.
Итак, теперь мы хотели бы либо
-
способ найти все случаи, когда сопоставляются указатели на функции (но не указатели данных) (поэтому мы можем вместо этого сравнивать их с FP_NULL, которые мы будем определять как 32-разрядные 0), или
-
чтобы переопределить NULL таким образом, чтобы он поступал правильно.
-
(Или, я полагаю, обновите наш gcc-порт, чтобы обнаружить и правильно обработайте этот случай).
Я не могу придумать какой-либо подход, который работает для 1. Единственный подход, который я могу представить для 2, - это переопределить NULL как указатель функции 0, который был бы очень расточительным для подавляющего большинства сравнений, которые противоречат данным указатели. (32-разрядное сравнение - 4 команды, 16-разрядное сравнение - 1 инструкция).
Любые мысли или предложения?