Обнаружить использование макроса? (Ошибка) - PullRequest
9 голосов
/ 28 августа 2009

Это очень специфично, и немного сложно объяснить, и, скорее всего, невозможно, но здесь идет речь.

Я хочу реализовать . (Мой хобби-проект - реализация библиотеки Standard C .)

Наивный способ сделать это:

// in <errno.h>
extern int errno;

// in some .c file
int errno = 0;

Это работает. Но у этого есть один недостаток: если вызывается функция математической библиотеки, она всегда должна запросить состояние FPU после выполнения, чтобы установить errno в зависимости от ситуации. Это останавливает FPU в математических приложениях.

Стандарт C поддерживает ленивую оценку errno, сделав вместо этого макрос:

int * __errno();
#define errno *__errno()

Таким образом, errno устанавливается только тогда, когда его значение фактически запрашивается:

// "__errno()" returns the location of the current errno value,
// the "errno" macro turns it into a value.
x = errno;

Учитывая некоторую логику в остальной части библиотеки, статус FPU необходимо запрашивать только в том случае, если последняя вызванная библиотечная функция была на самом деле , используя FPU, и значение errno равно фактически запрашивается .

Пока все хорошо. Но наоборот, у меня болит голова:

errno = 0;

Значение errno не запрашивается вообще. Но __errno() этого не знает и запросит состояние FPU, если последняя вызванная библиотечная функция использовала FPU.

Прямо сейчас я не вижу способа избежать этого (т. Е. Чтобы макрос errno или функция __errno() как-то работали по-разному в зависимости от того, используются они слева или справа от оператора присваивания) и я почти согласен принять это.

Но, возможно, у кого-то из вас есть блестящая идея?

Ответы [ 3 ]

4 голосов
/ 28 августа 2009

Здесь нет блестящих идей, но afaik errno разрешено реализовывать через вызовы функций, чтобы сделать возможной поточно-ориентированную реализацию стандартной библиотеки. Я не думаю, что лениво запрашивать FPU - это хорошая идея: как избежать несогласованности в таких ситуациях:

  • набор errno
  • операции с плавающей точкой, которые устанавливают флаги ошибок
  • получить errno
  • получить флаги

Должен ли звонок на __errno() сбросить флажки или нет?

В соответствии со стандартом, должен ли errno быть установлен математическими функциями, определяется значение math_errhandling (в частности, math_errhandling & MATH_ERRNO).

Что бы я сделал, это сделал бы сообщение об ошибке необязательным с помощью директив препроцессора и позволил программисту установить значение math_errhandling во время компиляции. Это будет означать, что математические функции не могут быть статически скомпилированы заранее, но должны находиться в заголовке, что может быть хорошей идеей, если компиляторы без оптимизации во время компоновки могут встроить эти функции.

2 голосов
/ 28 августа 2009

Здесь у вас есть довольно хороший анализ того, почему весь механизм errno настолько неудовлетворителен. Подобный анализ можно найти и в «Стандартной библиотеке C» Кернигана.

Функциональная форма errno также необходима для поточно-ориентированных реализаций, где разные потоки имеют отдельные значения ошибок, доступ к которым осуществляется через поток * *

Ваш макрос, вероятно, должен иметь круглые скобки для безопасности:

#define errno (*__errno())
1 голос
/ 28 августа 2009

Больше комментариев, чем ответа, но без форматирования кода это было бы непонятно.

Если вы лениво проверяете флаги FPU, как бы вы поступили правильно (математические функции отличаются тем, что они гарантированно не изменяют errno, когда проблем нет)

errno = 0;
x = acos(y);
z = <exp>;
if (errno != 0) {
   /* can't come here even if y is a valid argument but <exp> modified the flags if it didn't call any functions */
}
...