2009-08-28 14 views
9

Jest to bardzo specyficzne i nieco trudne do wytłumaczenia, a całkiem możliwe niemożliwe, ale tutaj idzie.Wykrywanie użycia makra? (errno)

Chcę zaimplementować <errno.h>. (. Mój projekt hobby realizuje standardowe C biblioteki)

naiwny sposób, aby go o to:

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

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

To działa. Ma jednak jedną wadę: jeśli wywoływana jest funkcja biblioteki matematycznej, musi zawsze przesyłać kwerendę do stanu FPU po wykonaniu, aby odpowiednio ustawić errno. Powoduje to zatrzymanie FPU w ciężkich zastosowaniach matematycznych.

standardzie C popiera leniwe ocenę errno przez co makro zamiast:

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

ten sposób errno jest tylko "zestaw", gdy jego wartość jest rzeczywiście wniosek:

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

Biorąc pod uwagę pewną logikę w pozostałej części biblioteki, status FPU wymaga jedynie zapytania, jeśli ostatnia funkcja biblioteki nazywała się przy użyciu FPU, , a wartość errno jest rzeczywiście wymagana.

Do tej pory wszystko jest w porządku. Ale to jest na odwrót, że daje mi głowy:

errno = 0; 

Wartość errno nie jest wymagane w ogóle. Ale __errno() nie wie o tym i zapyta o stan FPU, jeśli ostatnia funkcja biblioteki wywołana używała FPU.

Teraz nie widzę sposobu, aby uniknąć sytuacji (czyli mają errno makro lub funkcji __errno() jakoś działa różnie w zależności od tego, czy są one wykorzystywane do lewej lub po prawej stronie operatora przypisania) oraz jestem prawie zadowolony, aby to zaakceptować.

Ale może któryś z was ma świetny pomysł?

Odpowiedz

4

Nie ma tu genialnych pomysłów, ale afaik errno może być implementowany za pośrednictwem wywołań funkcji, aby umożliwić implementację standardowej biblioteki w sposób bezpieczny dla wątków. Nie sądzę zapytań FPU leniwie jest dobrym pomysłem: Jak można uniknąć niespójności w sytuacjach takich jak ta:

  • ustawić errno
  • zmiennoprzecinkowych ops które ustawione flagi błędów
  • dostać errno
  • Otrzymuj flagi

Czy połączenie z __errno() wyczyści flagi, czy nie?

Zgodnie ze standardem, to czy errno musi być ustawiane przez funkcje matematyczne, jest określane przez wartość math_errhandling (konkretnie: math_errhandling & MATH_ERRNO).

Mogę zrobić, aby zgłaszanie błędów było opcjonalne w dyrektywach preprocesora i umożliwić programiście ustawienie wartości math_errhandling podczas kompilacji. Oznaczałoby to, że funkcje matematyczne nie mogą być wcześniej skompilowane statycznie, ale muszą znajdować się w nagłówku, co i tak może być dobrym pomysłem, aby umożliwić kompilatorom bez optymalizacji czasu łącza do wstawiania tych funkcji.

2

To, co tu masz, to dość dobra analiza, dlaczego cały mechanizm errno jest tak niezadowalający. Podobne analizy można znaleźć w "Standardowej bibliotece C" Kernighana.

Funkcjonalna forma errno jest również potrzebna do implementacji bezpiecznych dla wątków, gdzie różne wątki mają oddzielne wartości błędów dostępne za pośrednictwem specyficznego dla gwintów errno.

makra powinny prawdopodobnie nawiasy wokół niego dla bezpieczeństwa:

#define errno (*__errno()) 
1

Więcej komentarz niż odpowiedzi, ale bez formatowania kodu nie byłoby zrozumiałe.

Jeśli sprawdzasz leniwie flagi FPU, w jaki sposób zachowałbyś się tutaj (funkcje matematyczne są specjalne, ponieważ gwarantują, że nie modyfikują errno, gdy nie ma problemu)?

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 */ 
}