2013-03-24 3 views
12

Właśnie brałem test C++ i otrzymałem następujące pytanie:Test C++ - Czy znak 1 oznacza zawsze ujemny?

Pytanie: Jaki jest wynik tego programu?

#include <iostream> 
#include <stdint.h> 

using namespace std; 

int main() { 
    int a = 0; 
    for (int8_t i = 1; i > 0; i <<= 1) 
     a++; 
    cout << a; 
    return 0; 
} 

wystąpiły następujące odpowiedzi do wyboru

  • Undefined Behavior
  • Błąd kompilacji

W "poprawne "odpowiedź brzmiała 7. Jeśli w odpowiedziach było" zachowanie zdefiniowane przez implementację ", wybrałbym to, więc wybrałem niezdefiniowane zachowanie, które było najbliższe. Rozumiem, że w znak-i-magnitorze, dopełnienie 1 i uzupełnienie dwójki to odpowiedź 7. Ale czy standard C++ teoretycznie nie zezwala na jakiekolwiek inne reprezentacje liczbowe? Na przykład znak i wielkość, ale 0 oznacza minus?

Czy mam rację, że prawdziwą poprawną odpowiedzią na to pytanie powinno być zachowanie zdefiniowane w ramach realizacji, a jeśli nie, proszę wyjaśnić, dlaczego odpowiedź brzmi 7 niezależnie od implementacji?

Czytałem komentarze na pytanie i wydaje się, że początkowo rodzaj a było char, który najwyraźniej wzbudził wiele skarg czy char jest podpisany, czy nie, więc testsetter zmienił go do int8_t. Jako pytanie premiowe, jest <stdint.h> częścią C++? O_O

+0

'' jest częścią C++ (dołączono do kompatybilności z C). Istnieje jego wersja C++, ''. –

+0

Każda rozsądna implementacja C++ powinna zawierać 'stdint.h', ale w C++ 11 jest oficjalnie' cstdint'. (@AlexeyFrunze: tylko C++ 11!) –

+2

[Implementacje nie muszą nawet podawać "int8_t"] (http://stackoverflow.com/a/5254321/168175) – Flexo

Odpowiedz

18

Powiedziałbym, że jest niezdefiniowany (a nie definiowany przez implementację) z innego powodu.

od 5,8: 3

Wartość E1 << E2 E1 jest przesuwany w lewo pozycje bitowe E2; wolne bity są wypełnione zerami. Jeśli E1 ma niepodpisany typ, wartość wyniku to E1 × 2 E2 , zredukowana wartość modulo o więcej niż maksymalna wartość reprezentowana w typie wyniku. W przeciwnym razie, jeśli E1 ma podpisany typ i nieujemną wartość, a E1 × 2 E2 jest reprezentowalne w typie wyniku, to jest to wynikowa wartość; w przeciwnym razie zachowanie jest niezdefiniowane.

+0

Uważam, że powoduje to, że zarówno UB, jak i błąd kompilatora są poprawne, ponieważ nie określają, którego kompilatora używa. – Flexo

+2

Nie, to niezdefiniowane zachowanie i nic więcej. Oczywiście kompilator może dowolnie łączyć się z UB (włączając w to miły, prosty błąd kompilacji), ale jeśli pytanie brzmi, co ISO C++ mówi, że powinien to być wynik tego programu, to jedyną poprawną odpowiedzią jest UB. :) – jalf

+0

Myślę, że brakuje ci znaku '^' w pierwszym 'E1 x 2 E2'. – 0x499602D2

7

Jeśli implementacja zapewnia opcjonalny int8_t, odpowiedź powinna być poprawna, z C99 draft, której odniesienia do C++ 11 dotyczące stdint;

7.18.1.1 Dokładna szerokości liczby całkowite

Nazwa typedef intN_t oznacza podpisaną typu całkowitą o szerokości N, NO bitów dopełniających, a uzupełnienie dwójkowe przedstawienie. Zatem int8_t oznacza liczbę całkowitą ze znakiem o nazwie o szerokości dokładnie 8 bitów.

+2

Cóż, nie odnosi się to do innego ważnego faktu, co dzieje się, gdy przesuwasz 1 do bitu znaku. I faktycznie to jest UB. –

+2

Jest to jednak interesujące. Czy dotyczy to tylko typów 'intN_t'? Czy też C11 również wymaga "normalnych" typów całkowitych jako uzupełnienia dwójki? – jalf

+0

Nawiasem mówiąc, jestem prawie pewien, że C++ 11 nie odwołuje się do C11. Czy raczej nie odwołałoby się do C99? – jalf

3

Ponieważ natychmiastowe pytanie odpowiedział, będę odpowiedzieć na pytanie bonus: <stdint.h> jest nagłówek C, która jest dostępna w języku C++. Zamiast tego należy użyć nowoczesnego nagłówka C++ <cstdint>.