2010-08-09 11 views
10

Obecnie pracuję nad projektem C, który musi być dość przenośny w różnych środowiskach budowlanych. Projekt jest ukierunkowany na systemy zgodne z POSIX na hostowanym środowisku C.Ścisły test zgodności ISO C

Jednym ze sposobów osiągnięcia wysokiego stopnia przenośności jest kodowanie zgodnie z wybranym standardem, ale trudno jest określić, czy dana jednostka tłumaczeniowa jest ściśle zgodna z ISO C. Na przykład może to spowodować naruszenie niektórych tłumaczeń ograniczenia lub może polegać na niezdefiniowanym zachowaniu, bez żadnego komunikatu diagnostycznego ze środowiska kompilacji. Nie jestem nawet pewien, czy możliwe jest sprawdzenie ścisłej zgodności dużych projektów.

Mając to na uwadze, czy jest jakiś kompilator, narzędzia lub metody testowania ścisłym ISO C zgodności w ramach danego standardu (na przykład, C89 lub C99) jednostki tłumaczenia?

Każda pomoc jest doceniana.

Odpowiedz

4

Zazwyczaj niemożliwe jest znalezienie nieokreślonego zachowania podczas wykonywania. Na przykład, rozważmy

void foo(int *p, int *q) 
{ 
    *p = (*q)++; 
    ... 

który jest niezdefiniowana jeśli p == q. To, czy może się zdarzyć, nie może zostać ustalone z wyprzedzeniem bez rozwiązania problemu zatrzymania.

(Zmieniano naprawić błąd jakim zauważył. Dzięki CAF).

+0

Twój przykład jest fantastyczny. Nigdy nie myślałem o tak prostych wyrażeń wskaźnikowych. Wierzyłem, że każdy taki nieokreślony stan może zostać wykryty w czasie parsetu. – alecov

+3

Twój przykład jest w porządku, nawet jeśli 'p == q' - być może miałeś na myśli' * p = (* q) ++ ', który jest niezdefiniowany jeśli' p == q'? – caf

3

Niezupełnie. Standard C nie określa żadnych absolutnych minimalnych limitów dla jednostek tłumaczeniowych, które muszą zostać zaakceptowane. Jako takie, idealnie dokładne sprawdzanie byłoby trywialne napisać, ale całkowicie bezużyteczne w praktyce:

#include <stdio.h> 

int main(int argc, char **argv) { 
    int i; 
    for (i=1; i<argc; i++) 
     fprintf(stderr, "`%s`: Translation limit (potentially) exceeded.\n", argv[i]); 
    return 0; 
} 

Tak, ten odrzuca wszystko, nie ważne jak błahe. Jest to zgodne z normą. Jak już powiedziałem, w praktyce jest to całkowicie bezużyteczne. Niestety, naprawdę nie można zrobić nic lepszego - gdy zdecydujesz się na przeniesienie do innej implementacji, możesz uruchomić jakiś dziwny limit zasobów, którego nigdy wcześniej nie widziałeś, a więc dowolny napisany kod (aż do " hello world ") może potencjalnie przekroczyć limit zasobów, mimo że jest dozwolony przez dziesiątki, a nawet setki kompilatorów na/dla dużo mniejszych systemów.

Edit:

Dlaczego program "Hello World" nie jest ściśle zgodny

Po pierwsze, warto ponownie podając definicję "ściśle zgodny": „Ściśle Conforming program powinien używać tylko tych, cechy języka i biblioteki określone w niniejszej Normie Międzynarodowej. 2) Nie może generować danych wyjściowych zależnych od jakichkolwiek nieokreślonych, niezdefiniowanych lub zdefiniowanych w ramach implementacji zachowań i nie może przekraczać żadnego minimalnego limitu implementacji. "

W rzeczywistości numer z powodów "Witaj, Świat" nie jest ściśle zgodny. Po pierwsze, jak sugerowano powyżej, minimalne wymagania dotyczące limitów implementacji są całkowicie bez znaczenia - chociaż musi być jakiś program, który spełnia pewne granice, które zostaną zaakceptowane, inny program musi zostać zaakceptowany, nawet jeśli nie spełnia wymagań. nawet zbliżyć się do którejkolwiek z tych granic. Biorąc pod uwagę sposób, w jaki wymóg ten jest określony, można kwestionować (w najlepszym przypadku), czy istnieje coś takiego jak program, który nie przekracza żadnego minimalnego limitu implementacji, ponieważ norma tak naprawdę nie definiuje żadnych minimalnych ograniczeń implementacji.

Po drugie, w fazie 1 tłumaczenia: "Pliki wielobajtowe w fizycznym pliku źródłowym są odwzorowywane, w sposób określony w ramach implementacji, na zestaw znaków źródłowych ..." (§5.1.1.2/1). Od "Hello, World!" (lub dowolny inny wariant) jest dostarczany w pliku źródłowym jako literał łańcuchowy, może być (jest) zmapowany w sposób określony przez implementację do zestawu znaków źródłowych. Implementacja może dowolnie decydować, że (dla przykładu idiotycznego) literały łańcuchowe będą kodowane ROT13, i dopóki ten fakt jest odpowiednio udokumentowany, jest to całkowicie uzasadnione.

Po trzecie, dane wyjściowe są zwykle zapisywane przez stdout. stdout to strumień tekstowy. Zgodnie ze standardem: "Znaki mogą być dodawane, zmieniane lub usuwane na wejściach i wyjściach, aby pasowały do ​​różnych konwencji reprezentujących tekst w środowisku hosta." Tak więc nie musi występować jedna do jednej korespondencji między znakami w strumieniu i w reprezentacji zewnętrznej. " (§7.19.2/2) Jako takie, implementacja może (na przykład) wykonać kompresję Huffmana na wyjściu (w poniedziałek, środę lub piątek).

Mamy więc (co najmniej) trzy różne punkty, w których wynik "Cześć, Świat!" zależy od cech określonych przez implementację - każda z nich uniemożliwiłaby jej dopasowanie definicji ściśle zgodnego programu.

+0

To nie jest zgodne ze standardem. Zobacz §5.2.4.1 Limity tłumaczeń. –

+0

@Stephen: tak, jest. Wymaganie jest następujące: "Implementacja musi być w stanie przetłumaczyć i wykonać co najmniej jeden program, który zawiera co najmniej jedną instancję każdego z następujących ograniczeń:". Tylko * jeden * określony program - a nawet nie ma wymogu udokumentowania tego, co to jest program. Każda możliwa operacja może zakończyć się niepowodzeniem, z wyjątkiem jednej konkretnej, której nie trzeba identyfikować ... –

+1

ze standardu ISO C99, §4 Zgodność: "Program ściśle zgodny będzie wykorzystywał tylko te funkcje języka i biblioteki określone w niniejszym Norma międzynarodowa Nie może ona przynosić wyników zależnych od jakichkolwiek nieokreślonych, niezdefiniowanych lub zdefiniowanych w ramach wdrożenia zachowań i nie może przekraczać żadnego minimalnego limitu wdrażania. " Dlaczego zatem, w oczywisty sposób, prosta realizacja programu Hello World nie byłaby w tym przypadku ściśle zgodna? – alecov

0

gcc ma poziomy ostrzegawcze, które będą próbowały określić różne aspekty zgodności z ANSI. Ale kapelusz to tylko punkt wyjścia.

0

Możecie zacząć gcc -std=c99 lub gcc -ansi -pedantic.

0

Powodzenia z tym. Staraj się unikać liczb całkowitych ze znakiem, ponieważ:

int f(int x) 
{ 
return -x; 
} 

może wywoływać UB.