2014-09-12 11 views
6

strlen zwraca liczbę znaków, które poprzedzają kończący znak null. Implementacja strlen może wyglądać następująco:Czy strlen na łańcuchu z niezainicjowanymi wartościami nieokreślonego zachowania?

size_t strlen(const char * str) 
{ 
    const char *s; 
    for (s = str; *s; ++s) {} 
    return(s - str); 
} 

Ta szczególna realizacja dereferences s, gdzie s może zawierać wartości nieokreślony. Jest to równoznaczne z tym:

int a; 
int* p = &a; 
*p; 

Tak na przykład, jeśli jeden z nich zrobić (co powoduje strlen dać niewłaściwego wyjścia):

char buffer[10]; 
buffer[9] = '\0'; 
strlen(buffer); 

Czy niezdefiniowane zachowanie?

+1

@ user2864740 Czy jesteś pewien, że ciąg * musi * zawiera jakąś wartość? Czy C nie może szczęśliwie zawiesić się na czytaniu przed pisaniem? – kay

Odpowiedz

2

Wywołanie standardowej funkcji strlen powoduje niezdefiniowane zachowanie. DR 451 wyjaśnia następująco:

funkcje biblioteczne będą wykazywać niezdefiniowanej zachowanie przy stosowaniu na wartości nieokreślonych

na bardziej pogłębionej dyskusji see this thread.

+0

Mój komentarz poniżej odnosi się do realizacji funkcji strlen przez plakat. Zgadzam się, że biblioteka standardowa ma inne ograniczenia lub swobody. –

+0

bufor [9] jest dość zdeterminowany ... – Basilevs

+0

@ KC-NH zaktualizował mój post, aby wyjaśnić, że mówię o standardowej funkcji 'strlen', a nie o pseudo implementacji OP. –

1

Nie, to nie jest niezdefiniowane zachowanie. Twoja funkcja strlen zatrzyma się przed końcem bufora. Jeśli twoja funkcja strlen odwołuje się do bufora [10], to tak, to jest niezdefiniowane.

Z pewnością będzie to nieoczekiwane zachowanie, ponieważ większość bufora zawiera losowe dane. "Undefined" to specjalne słowo dla osób piszących standardy językowe. Oznacza to, że wszystko może się zdarzyć, w tym błędy pamięci lub wyjście z programu. Nieoczekiwanie, mam na myśli to, że na pewno nie to, co chciał programista. W niektórych seriach wynik strlen może wynosić 3 lub może być 10.

0

Tak, to niezdefiniowane zachowanie. Od projektu normy C11, §J.2 „zachowanie niezdefiniowane”:

zachowanie jest niezdefiniowane w następujących okolicznościach:

...

Wartość przedmiotu z automatycznym czas przechowywania jest używany, gdy jest nieokreślony .

+2

Ten kod w rzeczywistości nie wykorzystuje nieokreślonych wartości ('buffer' nie jest nieokreślony, ale' buffer [0] 'jest). Jednak "strlen" używa wartości. Również ten aneks jest nienormatywny (ma to być rodzaj indeksu do znajdowania różnych przypadków UB). Tekst normatywny jest bardziej szczegółowy i ma pewne wyjątki, gdy nieokreślone użycie nie jest UB. –

+1

Obiekt jest nie tylko "nieokreślony", ale wartości są po prostu "nieokreślone", więc nic złego się nie stanie. –

2

Zachowanie wariantu, który wyświetlasz, jest dobrze zdefiniowane w tych okolicznościach.

  • Bajty z niezainicjowanych tablicy wszystkie wartości nieoznaczony, z wyjątkiem 10 elementu, który można ustawić na 0.
  • Uzyskiwanie nieokreślonej wartości byłoby tylko UB, jeśli adres obiektu bazowego nie zostanie nigdy wzięty lub jeśli wartość jest pułapką dla odpowiedniego typu.
  • Ponieważ jest to tablica, a dostęp do elementów tablicy odbywa się za pomocą arytmetyki wskaźników, tutaj pierwszy przypadek nie ma znaczenia.
  • Każda wartość char może być dostępna bez UB, klauzule o reprezentacjach pułapek w standardzie jawnie wykluczają wszystkie typy znaków z tego.
  • W ten sposób wartości, z którymi masz do czynienia, są po prostu "nieokreślone".
  • Czytanie nieokreślonych wartości może według niektórych członków komitetu normalizacyjnego C dawać za każdym razem różne wyniki, co niektórzy nazywają "w każdym razie". Ta właściwość nie ma znaczenia, ponieważ twoja funkcja odczytuje dowolną taką wartość co najwyżej raz.
  • Twój dostęp do elementów tablicy daje dowolną, ale ważną wartość: char.
  • Jesteś pewny, że twoja pętla for zatrzyma się najpóźniej na pozycji 9, więc nie przekroczysz swojej tablicy.

Nie można więc "złych" rzeczy poza widocznymi, jeśli używasz konkretnej wersji funkcji. Ale wywołanie funkcji, która wytwarza nieokreślone wyniki, z pewnością nie jest niczym, co chcesz zobaczyć w prawdziwym kodzie. Coś takiego tutaj prowadzi do bardzo subtelnych błędów i powinieneś tego unikać na wszelkie sposoby.

Powiązane problemy