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