2017-10-16 83 views
28

C11 §6.5.7 Paragraf 5:Czy "-1 >> 5;" nieokreślone zachowanie w C?

Wynik E1 >> E2 jest E1 prawo przesunięty E2 pozycje bitów. Jeśli E1 ma niepodpisany typ lub jeśli E1 ma podpisany typ i nieujemną wartość , wartość wyniku stanowi integralną część wartości z E1/2*^E2. Jeśli wartość E1 ma wartość typu podpisanego i ujemną: , wynikowa wartość jest definiowana przez implementację.

Ale Dokument viva64 referencyjna mówi:

int B; 
B = -1 >> 5; // unspecified behavior 

Pobiegłem ten kod na GCC i to zawsze daje wyjście -1.

więc powiedzieć, że norma „Jeśli E1 ma podpisaną rodzaj i wartość ujemną, wartość wynikowa jest realizacja zdefiniowanej”, ale to dokument powiedzieć, że -1>>5; jest nieokreślone zachowanie.

Więc, czy -1>>5; nieokreślone zachowanie w C? Który jest poprawny?

+17

Jeśli próbujesz napisać kod przenośny, rozróżnienie między definicją implementacji a nieokreśloną nie jest bardzo znaczące, więc kontrolerzy kodu traktują je w podobny sposób. – Barmar

+1

Jest zdefiniowany przez implementację. – chux

+0

@chux Więc ten dokument jest niepoprawny ?? – rsp

Odpowiedz

33

Obie są poprawne. Wdrożenie określonego zachowania jest szczególnym rodzajem nieokreślonego zachowania.

sekcji 3.4.1 the C standard który określa „zachowanie realizacji zdefiniowanej” Powołując:

zachowań realizacji zdefiniowanej

nieokreślone zachowanie gdzie każdy dokumenty wdrożeniowe jak wybór jest wykonany

PRZYKŁAD Przykładem zachowania definiowanego przez implementację jest t propaguje bit wyższego rzędu , gdy liczba ze znakiem jest przesunięta w prawo.

Z sekcji 3.4.4 określające zachowanie "nieokreślony":

nieokreśloną zachowanie

zastosowanie wartości nieokreślonej lub inne zachowania, gdzie ten Międzynarodowy Standard przewiduje dwa lub więcej możliwości i nakłada żadnych dalszych wymagań, które zostały wybrane w dowolnym przypadku

PRZYKŁAD Przykładem nieokreślonego zachowania jest kolejność, w jakiej oceniane są argumenty funkcji.

Co do GCC, zawsze otrzymasz tę samą odpowiedź, ponieważ operacja jest zdefiniowana przez implementację. Implementuje prawo przesunięcie liczb ujemnych poprzez rozszerzenie znak

Z GCC documentation:

Wyniki niektórych bitowe operacje na podpisanych liczb całkowitych (C90 6.3, C99 i C11 6,5).

bitowe operatorów ustawa o reprezentacji wartości w tym obu bitów znakowych i wartości, przy czym bit znaku jest uważany natychmiast powyżej wartości bitu o najwyższej wartości. Podpisano >> działa na liczb ujemnych przez rozszerzenie znaku.

Jako rozszerzenie do języka C, GCC nie korzysta z szerokości geograficznej danego w C99 i C11 tylko w leczeniu niektórych aspektów podpisał << jak niezdefiniowane. Jednak -fsanitize=shift (i -fsanitize=undefined) zdiagnozuje takie przypadki. Są one również diagnozowane tam, gdzie wymagane są stałe wyrażenia .

+1

To nie jest całkiem poprawne: "Określone zachowanie implementacji jest szczególnym rodzajem nieokreślonego zachowania". Jeśli zachowanie jest zdefiniowane przez implementację, standard określa, że ​​implementacja musi je zdefiniować i udokumentować, aby nie była ona nieokreślona. Nieokreślone zachowanie odnosi się do sytuacji, w których implementacja jest dowolna, ale nie musi dokumentować zachowania ani zapewniać spójności. –

+7

@R .. Z wyjątkiem definicji "zachowania zdefiniowanego przez implementację" w rzeczywistości używa dokładnie słów "nieokreślone zachowanie". Sądzę, że wymagająca dokumentacja nie jest uznawana za wymagającą "dalszych wymagań, które zostały wybrane". – aschepler

+1

Zinterpretowałbym definicję "zachowania definiowanego przez implementację", które cytowałeś jako wykluczające "nieokreślone zachowanie", tj. Oznaczające "jak dla nieokreślonego zachowania, ale także z tym wymaganiem". Wszakże definicja "nieokreślonego zachowania" obejmuje "nie nakłada żadnych dalszych wymagań, które zostały wybrane", jednak zachowanie zdefiniowane w ramach implementacji nakłada wymóg, aby dokument implementacyjny był wyborem, dlatego nie spełnia definicji "nieokreślonego zachowania" –

12

"Nieokreślone zachowanie" i "definicja wykonania" nie są sprzeczne. Oznacza to tylko, że standard C nie określa, co musi się wydarzyć, a różne implementacje mogą zrobić to, co uznają za "poprawne".

Wielokrotne uruchamianie tego samego kompilatora i uzyskiwanie tego samego wyniku oznacza, że ​​określony kompilatorjest spójny. Możesz uzyskać różne wyniki na innym kompilatorze.

+1

Żadne z nich nie jest podzbiorem drugiego. Jeśli działanie wywołuje "nieokreślone" zachowanie, implementacje są wymagane, aby wybrać spośród skończonego zestawu wyborów (np.'x() + y()' musi zachowywać się tak, jakby albo w pełni oceniało 'x()', a następnie ocenia 'y()', albo w pełni 'y()', a następnie 'x()'; to są tylko dwie opcje). Jeśli działanie wywołuje zachowanie "zdefiniowane przez implementację", implementacje są wymagane do udokumentowania określonego zachowania, ale mogą zrobić wszystko, co im się podoba, o ile dokumentują. – supercat