Jakie są typowe nieokreślone zachowania, o których programista C++ powinien wiedzieć? [zamknięte]

Jakie są typowe nieokreślone zachowania, o których programista C++ powinien wiedzieć?

Powiedz jak:

a[i] = i++;

Author: Peter Mortensen, 2008-12-15

11 answers

Pointer

  • Derefering a NULL pointer
  • dereferencja wskaźnika zwracanego przez" nowy " przydział wielkości zero
  • używanie wskaźników do obiektów, których okres życia się skończył (na przykład stosu przydzielonych obiektów lub usuniętych obiektów)
  • dereferencja wskaźnika, który nie został jeszcze definitywnie zainicjowany
  • Wykonywanie arytmetyki wskaźnika, która daje wynik poza granicami (powyżej lub poniżej) tablicy.
  • dereferencja wskaźnik w miejscu poza końcem tablicy.
  • Konwersja wskaźników na obiekty niezgodnych typów
  • używanie memcpy do kopiowania nakładających się buforów .

Przepełnienia bufora

    W zależności od tego, czy jest to obiekt, czy tablica, czy też tablica, czy tablica, czy tablica, są to obiekty o ujemnym przesunięciu, czy też obiekty o większym rozmiarze (przepełnienie stosu/sterty).]}

Przepełnienia Całkowite

  • Signed integer overflow
  • ocena wyrażenia, które nie jest zdefiniowane matematycznie
  • przesunięcie w lewo wartości o kwotę ujemną (przesunięcie w prawo o kwoty ujemne są zdefiniowane w implementacji)
  • przesunięcie wartości o kwotę większą lub równą liczbie bitów w liczbie (np. int64_t i = 1; i <<= 72 jest niezdefiniowane)

Typy, obsada i Const

  • Odlewanie wartości liczbowej na wartość, która nie może być reprezentowana przez typ docelowy (bezpośrednio lub poprzez static_cast)
  • za pomocą zmiennej automatycznej przed jej definitywnie przypisane (np., int i; i++; cout << i;)
  • używanie wartości dowolnego obiektu innego niż volatile lub sig_atomic_t przy odbiorze sygnału
  • próba modyfikacji ciągu znaków lub dowolnego innego obiektu const podczas jego życia
  • łączenie wąskiego z szerokim ciągiem literałów podczas wstępnego przetwarzania

Funkcja i szablon

  • nie zwracanie wartości z funkcji zwracającej wartość (bezpośrednio lub przez try-block)
  • wiele różnych definicji dla tej samej jednostki (Klasa, szablon, wyliczenie, funkcja inline, statyczna funkcja członka itp.)
  • nieskończona rekurencja w tworzeniu szablonów
  • wywołanie funkcji za pomocą różnych parametrów lub powiązania z parametrami i powiązaniem, które funkcja jest zdefiniowana jako za pomocą.

OOP

  • kaskadowe niszczenie obiektów o statycznym czasie przechowywania
  • wynik przypisania do częściowo nakładające się obiekty
  • rekurencyjne wprowadzanie funkcji podczas inicjalizacji jej statycznych obiektów
  • Wykonywanie wywołań funkcji wirtualnych do czystych funkcji wirtualnych obiektu z jego konstruktora lub destruktora
  • odnosi się do niestatycznych elementów obiektów, które nie zostały zbudowane lub zostały już zniszczone

Plik źródłowy i wstępne przetwarzanie

  • niepusty plik źródłowy, który nie kończy się znakiem nowej linii lub kończy się znakiem backslash (przed C++11)
  • ukośnik wsteczny, po którym następuje znak, który nie jest częścią podanych kodów specjalnych w stałej znakowej lub łańcuchowej (jest to implementacja zdefiniowana w C++11).
  • przekroczenie limitów implementacji (liczba zagnieżdżonych bloków, liczba funkcji w programie, dostępna przestrzeń stosu ...)
  • wartości liczbowe preprocesora, które nie mogą być reprezentowane przez long int
  • Dyrektywa przetwarzania wstępnego po lewej stronie makra podobnego do funkcji definicja
  • Dynamiczne generowanie zdefiniowanego tokena w wyrażeniu #if

Do sklasyfikowania

  • wywołanie exit podczas niszczenia programu ze statycznym czasem przechowywania
 233
Author: Diomidis Spinellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:24

Kolejność oceniania parametrów funkcji jest nieokreślone zachowanie . (Nie spowoduje to awarii programu, wybuchu lub zamówienia pizzy... w przeciwieństwie do undefined behavior .)

Jedynym wymogiem jest to, że wszystkie parametry muszą być w pełni ocenione przed wywołaniem funkcji.


To:

// The simple obvious one.
callFunc(getA(),getB());

Może być równoważne temu:

int a = getA();
int b = getB();
callFunc(a,b);

Lub to:

int b = getB();
int a = getA();
callFunc(a,b);

Może być albo; To zależy od kompilatora. Wynik może mieć znaczenie, w zależności od skutków ubocznych.

 31
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 04:26:33

Kompilator może dowolnie porządkować części ewaluacyjne wyrażenia (zakładając, że znaczenie nie ulegnie zmianie).

Z pierwotnego pytania:

a[i] = i++;

// This expression has three parts:
(a) a[i]
(b) i++
(c) Assign (b) to (a)

// (c) is guaranteed to happen after (a) and (b)
// But (a) and (b) can be done in either order.
// See n2521 Section 5.17
// (b) increments i but returns the original value.
// See n2521 Section 5.2.6
// Thus this expression can be written as:

int rhs  = i++;
int lhs& = a[i];
lhs = rhs;

// or
int lhs& = a[i];
int rhs  = i++;
lhs = rhs;

Zamek Podwójnie sprawdzony. I jeden łatwy błąd do popełnienia.

A* a = new A("plop");

// Looks simple enough.
// But this can be split into three parts.
(a) allocate Memory
(b) Call constructor
(c) Assign value to 'a'

// No problem here:
// The compiler is allowed to do this:
(a) allocate Memory
(c) Assign value to 'a'
(b) Call constructor.
// This is because the whole thing is between two sequence points.

// So what is the big deal.
// Simple Double checked lock. (I know there are many other problems with this).
if (a == null) // (Point B)
{
    Lock   lock(mutex);
    if (a == null)
    {
        a = new A("Plop");  // (Point A).
    }
}
a->doStuff();

// Think of this situation.
// Thread 1: Reaches point A. Executes (a)(c)
// Thread 1: Is about to do (b) and gets unscheduled.
// Thread 2: Reaches point B. It can now skip the if block
//           Remember (c) has been done thus 'a' is not NULL.
//           But the memory has not been initialized.
//           Thread 2 now executes doStuff() on an uninitialized variable.

// The solution to this problem is to move the assignment of 'a'
// To the other side of the sequence point.
if (a == null) // (Point B)
{
    Lock   lock(mutex);
    if (a == null)
    {
        A* tmp = new A("Plop");  // (Point A).
        a = tmp;
    }
}
a->doStuff();

// Of course there are still other problems because of C++ support for
// threads. But hopefully these are addresses in the next standard.
 27
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-15 15:58:31

Moim ulubionym jest "nieskończona rekurencja w instancjach szablonów", ponieważ uważam, że jest to jedyna taka, w której niezdefiniowane zachowanie występuje w czasie kompilacji.

 5
Author: Daniel Earwicker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-15 08:17:32

Przypisanie do stałej po rozbiciu const Ness za pomocą const_cast<>:

const int i = 10; 
int *p =  const_cast<int*>( &i );
*p = 1234; //Undefined
 5
Author: yesraaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-07 10:53:52

Oprócz niezdefiniowanego zachowania, Istnieje również równie paskudne zdefiniowane w implementacji zachowanie.

Nieokreślone zachowanie występuje, gdy program robi coś, czego wynik nie jest określony przez standard.

Implementation-defined behaviour to działanie programu, którego wynik nie jest zdefiniowany przez standard, ale które implementacja jest zobowiązana udokumentować. Przykładem jest "wielobajtowe literały znaków", z pytania o przepełnienie stosu czy istnieje kompilator C, który tego nie skompiluje?.

Zachowanie zdefiniowane w implementacji gryzie cię tylko wtedy ,gdy rozpoczynasz portowanie (ale aktualizacja do nowej wersji kompilatora również jest portowaniem!)

 5
Author: Constantin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:48

Zmienne mogą być aktualizowane tylko raz w wyrażeniu (technicznie raz między punktami sekwencji).

int i =1;
i = ++i;

// Undefined. Assignment to 'i' twice in the same expression.
 4
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 21:15:50

Podstawowe zrozumienie różnych ograniczeń środowiskowych. Pełny wykaz znajduje się w sekcji 5.2.4.1 specyfikacji C. Oto kilka;

  • 127 parametrów w jednej definicji funkcji
  • 127 argumentów w jednym wywołaniu funkcji
  • 127 parametrów w jednej definicji makra
  • 127 argumentów w jednym wywołaniu makra
  • 4095 znaków w logicznej linii źródłowej
  • 4095 znaków w ciągu znaków literalny lub szeroki ciąg literalny (po konkatenacja)
  • 65535 bajtów w obiekt (tylko w środowisku hostowanym)
  • 15 poziomów dla # includedfiles
  • 1023 etykiety Etui na przełącznik oświadczenie (z wyłączeniem tych dla anynested Switch statements)

Byłem trochę zaskoczony limitem 1023 etykiet przypadków dla instrukcji switch, mogę forsee, że jest przekroczony dla generowanego kodu / lex / parserów dość łatwo.

Jeśli te limity zostaną przekroczone, masz nieokreślone zachowanie (awarie, wady zabezpieczeń, itd...).

No tak, Wiem, że to ze specyfikacji C, ale C++ dzieli te podstawowe podpory.

 3
Author: RandomNickName42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 21:19:12

Używanie memcpy do kopiowania między nakładającymi się regionami pamięci. Na przykład:

char a[256] = {};
memcpy(a, a, sizeof(a));

Zachowanie jest niezdefiniowane zgodnie ze standardem C, który jest podzbiorem standardu C++03.

7.21.2.1 funkcja memcpy

Synopsis

1 / # include void * memcpy(void * restrict s1, const void * restrict s2, size_t n);

Opis

2 / funkcja memcpy kopiuje n znaków z obiektu wskazywanego przez s2 do obiektu / align = "left" / S. BUS Jeśli kopiowanie odbywa się między obiektami, które nachodzą na siebie, zachowanie jest nieokreślone. Zwraca 3 funkcja memcpy zwraca wartość s1.

7.21.2.2 funkcja memmove

Synopsis

1 # include void * memmove(void *S1, const void * s2, size_t n);

Opis

2 funkcja memmove kopiuje n znaków z obiektu wskazywanego przez s2 do obiektu wskazywanego przez s1. Kopiowanie odbywa się tak, jakby n znaków z obiektu wskazywanego przez s2 są najpierw kopiowane do tymczasowa tablica n znaków, która nie nakłada się na obiekty wskazywane przez s1 i s2, a następnie n znaków z tymczasowego tablice są kopiowane do obiektu wskazywanego przez s1. Returns

3 funkcja memmove Zwraca wartość s1.

 2
Author: John Dibling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-26 16:10:25

Jedynym typem, dla którego C++ gwarantuje rozmiar jest char. A rozmiar to 1. Rozmiar wszystkich innych typów jest zależny od platformy.

 2
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 21:13:01

Obiekty poziomu przestrzeni nazw w różnych jednostkach kompilacji nigdy nie powinny zależeć od siebie podczas inicjalizacji, ponieważ ich kolejność inicjalizacji jest niezdefiniowana.

 2
Author: yesraaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 21:18:08