2015-06-10 12 views
6

Wynik niektórych rzutów wskaźnika jest opisany jako nieokreślony. Na przykład [expr.static.cast]/13Jak zachowuje się nieokreślona konwersja wskaźnika w C++ 14?

prvalue typu „wskaźnik do CV1 próżni” może być przekształcony w prvalue typu „wskaźnik do CV2 T” [...] Jeżeli oryginalna wartość wskaźnika reprezentuje adres A bajtu w pamięci, a A spełnia wymóg wyrównania T, a wynikowa wartość wskaźnika reprezentuje ten sam adres, co oryginalna wartość wskaźnika, czyli A. Wynik dowolnego innego takiego wskaźnika konwersja jest nieokreślona.

Moje pytanie brzmi: w przypadku, gdy ustawienie jest nie spełnione, jakie są możliwe wyniki?

Czy na przykład dozwolone są następujące wyniki?

  • null pointer
  • nieprawidłowa wartość wskaźnika (czyli wskaźnik, który nie wskazuje na przydzielonej przechowywania wielkości T)
  • ważny wskaźnik do T w zupełnie oddzielnej części pamięci

przykładowy kod dla odniesienia:

#include <iostream> 

int main(int argc, char **argv) 
{ 
    int *b = (int *)"Hello, world"; // (1) 

    *b = -1;       // (2) 
    std::cout << argc << '\n'; 
} 

Linia (1) wyzwala mój powyższy cytat z [expr.static.cast]/13, ponieważ jest to reinterpret_cast która jest objęta [expr.reinterpret.cast]/7, który określa konwersję w zakresie static_cast ing przez void *.

Jeśli nieokreślony wynik może być nieprawidłową wartością wskaźnika, linia (1) może spowodować pułapkę sprzętową. (Numer referencyjny: N4430, który wyjaśnia podobne sformułowanie w C++ 14 i C++ 11).

Pytanie uzupełniające: Czy istnieje przypadek, w którym linia 1 spowodowałaby niezdefiniowane zachowanie? (Nie sądzę, na tym etapie, ponieważ odczyt wartości wskaźnika C++ 14 jest zdefiniowany przez implementację lub powoduje pułapkę sprzętową).


Również interesujące jest to, że linia (2) będzie w większości przypadków być niezdefiniowane zachowanie ze względu na ścisłą naruszeniem aliasing (i być może innych przyczyn zbyt), jednak jeśli nieokreślony wynik może być &argc to ten program może wyjście -1 bez wyzwalania niezdefiniowany zachowanie!

+6

Err, jest nieokreślony. – EJP

+1

"... wtedy ten program mógłby wypisać' -1' bez wywoływania niezdefiniowanego zachowania "to dziwne - i powiedziałbym niewłaściwe - sposób na wyrażenie go. Linia (2) zawsze powoduje niezdefiniowane zachowanie. "Niezdefiniowane zachowanie" oznacza, że ​​każde zachowanie programu będzie zgodne ze specyfikacją, w tym zachowanie wyjścia -1. "Nieokreślona wartość" jest wartością (nie zachowaniem), której specyfikacja nie ogranicza, a implementacja nie musi dokumentować. – Nemo

+0

@Noo w jaki sposób linia 2 powoduje UB (jeśli 'b' ma wartość' & argc') –

Odpowiedz

3

Moje pytanie brzmi: w przypadku, gdy wyrównanie nie jest spełnione, jakie są możliwe wyniki?

O ile mogę powiedzieć, N4303: Pointer safety and placement new częściowo odpowiada na to pytanie, choć nieco pośrednio. Ten dokument odnosi się do CWG issue 1412: Problems in specifying pointer conversions, który spowodował zmiany w [expr.static.cast]/13 że można odwołać, specjalnie dodając:

[...] Jeśli oryginalna wartość wskaźnik reprezentujący skierować bajtu w pamięci i spełnia warunek wyrównanie T, następnie uzyskany wskaźnik wartość reprezentuje ten sam adres co pierwotnej wartości wskaźnika, czyli A. wynikiem jakiejkolwiek innej takiej konwersji wskaźnika jest nieokreślona. [...]

W odniesieniu do tej zmiany N4303 mówi (podkr):

Przed przyjęciem rezolucji dla DR 1412 [CWG1412], wartość bp jest nieokreślona w momencie jej inicjalizacji, a następnie przechodzi na operatora new za pośrednictwem nowego wyrażenia. Wymieniony wskaźnik może być pusty, niewystarczająco wyrównany lub w inny sposób niebezpieczny w użyciu.

Więc nieokreślona konwersji może skutkuje:

  • null pointer
  • Niewystarczające wyrównany wskaźnik
  • wskaźnik, który jest niebezpieczny w użyciu
+0

"Wskaźnik, który jest niebezpieczny w użyciu" wydaje się być zła. "nieprawidłowa wartość wskaźnika" jest na pewno wskaźnikiem, który jest niebezpieczny w użyciu; jakie są inne możliwości? –

+0

"Niewystarczająco wyrównany wskaźnik" - o ile widzę, poza zwykłą regułą aliasingu nie ma innego tekstu, który uniemożliwiałby użycie takiego wskaźnika. Tylko ta klauzula, którą omawiamy, może potencjalnie zapobiec stworzeniu takiego wskaźnika. Tak więc, prawdopodobnie, na maszynach, które wymuszają wyrównanie sprzętowe, nie mogą zwracać niewystarczająco wyrównanego wskaźnika. –

+0

@MattMcNabb: Wystarczy wymienić kilka innych możliwości: wskaźnik, który nie jest równy samemu sobie lub wskaźnik, dla którego podział arytmetyczny wskaźnika (np. P + 1-1! = P) – MSalters

Powiązane problemy