2014-12-04 21 views
6

W szczególności, mam następujący kod w interfejsie biblioteki:Czy dodanie enumeratorów do enum łamie ABI?

typedef enum 
{ 
    state1, 
    state2, 
    state3, 
    state4, 
    state5, 
    state_error = -1, 
} State; 

ja zabronione złamać ABI. Jednak chcę dodać state6 i state7. Czy złamie ABI?

Znalazłem here wskazówkę, ale mam wątpliwości, czy to moja sprawa?

Można ...

  • dopisywał rachmistrzów do istniejącego wyliczenia.

Wyjątek: jeśli prowadzi to do wybrania przez kompilator większego bazowego typu wyliczenia, oznacza to, że zmiana jest niekompatybilna z binarnymi. Niestety, kompilatory mają pewną swobodę wyboru bazowego typu, więc z perspektywy projektowania API zaleca się dodać moduł wyliczający Max .... z wyraźną dużą wartością (= 255, = 1 < < 15, itp.), Aby utworzyć interwał liczbowych wartości wyliczających, które gwarantują dopasowanie do wybranego podstawowego typu, niezależnie od tego, jakie mogą być.

+2

'state3' ma trzy różne kody? – Deduplicator

+1

Dodanie nowego wyliczenia przy pozostawieniu istniejących samodzielnie nie powinno naruszać zgodności ABI, o ile rozmiar podstawowego tekstu nie zmienia się w wyniku dodatków. Tak mówi twój cytowany materiał. –

Odpowiedz

10

Twoje pytanie jest dobrym przykładem, dlaczego długotrwałe utrzymywanie zgodności ABI jest trudnym zadaniem. Sedno problemu polega na tym, że kompatybilność zależy nie tylko od danego typu, ale także od tego, w jaki sposób jest on stosowany w prototypach funkcji/metod lub typach złożonych (np. Strukturach, związkach itp.).

(1) Jeśli wyliczenie jest używane gdziekolwiek jako wyjście z biblioteki (np. Wartość zwracana lub funkcja wypełniająca pewien adres podany przez parametr wyjściowy a.k.a wywołującego), zmiana spowodowałaby złamanie ABI. Rozważmy wyliczenie, że jest to umowa, w której "aplikacja nigdy nie widzi wartości innych niż wymienione". Dodanie nowego członka enum złamałoby tę umowę, ponieważ stare aplikacje mogły teraz widzieć wartości, z którymi nigdy nie zliczono.

(2) Jeśli wyliczenie jest używane wyłącznie jako dane wejściowe do biblioteki (np. Jako parametr funkcji, która po prostu zmienia zachowanie funkcji/biblioteki), to zachowuje zgodność: Zmieniłeś umowę w sposób, który nigdy nie zaszkodzi klientowi, czyli aplikacji wzywającej. Stare aplikacje nigdy nie będą korzystały z nowej wartości i staną się stare, nowe aplikacje będą miały więcej opcji.

+0

Innymi słowy, można osłabić wymagania bibliotek bez szkody, ale nie można osłabić gwarancji. Uważaj jednak na ludzi, którzy polegają na walidacji parametrów w celu odrzucenia nieprawidłowych danych wejściowych w określony sposób. Te istnieją ... – Deduplicator

3

Cytat faktycznie jest twoją sprawą. Proste dodają nowe wartości wyliczeniowe na końcu (ale przed state_error, ponieważ ma inną wartość) i powinny być zgodne binarnie, chyba że, jak wspomniano w cytowanej ofercie, kompilator zdecyduje się użyć typu o innym rozmiarze, który robi Wydaje się prawdopodobne w przypadku takiego małego wyliczenia.

Najlepszym sposobem jest sprawdzenie: prosty sizeof(State) wykonany przed i po zmianach powinien wystarczyć (chociaż możesz również chcieć sprawdzić, czy wartości są nadal takie same).

2

Spójrz na najwyżej ceniony enumeratora-ID: state3 to 2.

Oznacza to, że nawet jeśli kompilator powinien wybrało char jako typ bazowego, można wygodnie dopasować 100+ dodatkowych identyfikatorów wyliczający tam, bez ryzyka uszkodzenia zgodności binarnej.

To wstępnie zakłada, że ​​użytkownicy podają wartość iteratora, zamiast kiedykolwiek czytając jedną.