2013-02-14 12 views
5

Według mojego zrozumienia, strcmp() (bez "n"), po wyświetleniu znaku pustego w obu argumentach, natychmiast przestaje przetwarzać i zwraca wynik.
Dlatego jeśli jeden z argumentów jest znany z 100% pewnością, że jest zakończony znakiem NUL (np. Jest literałem łańcuchowym), nie ma żadnej korzyści bezpieczeństwa przy użyciu strncmp() (z "n") z wywołaniem do strlen() jako część trzeciego argumentu, aby ograniczyć porównanie do znanej długości ciągu, ponieważ strcmp() nigdy nie będzie więcej znaków niż w łańcuchu kończącym znane.Czy strlen() w wyrażeniu strncmp() pokonuje cel użycia strncmp() over strcmp()?

W rzeczywistości wydaje mi się, że wezwanie do strncmp() którego długość argument jest strlen() na jednym z dwóch pierwszych argumentów różni się tylko od przypadku strcmp() tym, że marnuje czas liniowy w rozmiarze znanym-kończącym ciąg znaków przez oszacowanie wyrażenia strlen().

Rozważmy: Kod

Próbka A: kod

if (strcmp(user_input, "status") == 0) 
    reply_with_status(); 

Próbka B:

if (strncmp(user_input, "status", strlen("status")+1) == 0) 
    reply_with_status(); 

Czy jest jakaś korzyść tych pierwszych na drugi? Ponieważ widzę to w kodach innych osób: lot.

Czy mam błędne zrozumienie działania tych funkcji?

Odpowiedz

5

W danym przykładzie, powiedziałbym, że to szkodliwe używać strncmp powodu:

  • Korzystanie strlen sposób skanowania i tak
  • Powtórzenie ciągu dosłownym "status"
  • Dodanie 1, aby upewnić że łańcuchy są rzeczywiście równe

Wszystkie te elementy powodują bałagan, w żadnym z tych przypadków nie można by chronić d z przepełnienia user_input, jeśli rzeczywiście był krótszy niż 6 znaków i zawierał te same znaki co ciąg testowy.

To byłoby wyjątkowe. Jeśli wiesz, że twój ciąg wejściowy zawsze ma więcej pamięci niż liczba znaków w łańcuchu testowym, to nie martw się. W przeciwnym razie możesz się martwić, a przynajmniej rozważyć. strncmp jest przydatny do testowania rzeczy wewnątrz dużych buforów.

Moje preferencje dotyczą czytelności kodu.

+0

Oddałbym ci głos, ale nie mam wystarczającej reputacji. : p Dziękuję za szczegółową odpowiedź! – cvp

+0

Niektóre/większość kompilatorów może obliczyć 'strlen (" status ")' jako stałą wartość. W przeciwnym razie, zgadzam się. –

4

Tak jest. Jeśli użyjesz strlen w strncmp, będzie on przechodził przez wskaźnik, dopóki nie zobaczy wartości pustej w łańcuchu. To sprawia, że ​​jest funkcjonalnie równoważny dla strcmp.

+0

chciałbym podać takie same wtedy +1. kiedy używam drugiego argumentu strncmp to max rozmiar user_input (często tylko sizeof (user_input) gdy user_input to char []), to jest opiekunem. –

0

Teraz zgadzam się, że nie jest to szczególnie użyteczne użycie funkcji strncmp(), i nie widzę żadnej korzyści w tym porównaniu przez strcmp().

Jeśli jednak zmienimy kod, usuwając +1 po strlen, to zacznie być użyteczny.

strncmp(user_input, "status", strlen("status")) 

ponieważ porównuje pierwsze 6 znaków user_input z `„status”- który, przynajmniej czasami ma sens.

Tak więc, jeśli jest tam +1, staje się regularnym strcmp - a to tylko strata czasu na obliczanie długości. Ale bez +1, jest to całkiem przydatne porównanie (w odpowiednich okolicznościach).

+0

Bardzo dobry punkt. W ten sposób zaimplementowane są te "typowe słowa polecenia, aby je rozróżnić", nón? 'if (! strncmp (command," st ", 2))/* ... * /', zakładając, że nie masz innych poleceń zaczynających się na "st". Dzięki za twoją odpowiedź! – cvp

+0

Tak, chociaż to raczej bardziej przypomina ten pseudo-kod 'count = 0; for (i: all_commands) {if (match_cmd (command, i)) {dopasowany = i; count ++; }} if (count == 1) execute_command (i); else print ("trzeba wpisać więcej ...");' –

4

W konkretnym przypadku, który podałeś, w rzeczywistości jest bezużyteczny. Jednak niewielka zmiana jest bardziej powszechne:

if (strncmp(user_input, "status", strlen("status")) == 0) 
    reply_with_status(); 

Ta wersja tylko sprawdza, czy user_inputrozpoczyna z "status", a więc ma różne semantykę.

+0

Bardzo dobry punkt, o którym zapomniałem wspomnieć.Dziękuję za odpowiedź! – cvp

+0

Ach, byłeś szybszy! Co mówią o wspaniałych umysłach ... – wildplasser

0

Strncmp() ma ograniczone zastosowanie. Normalna funkcja strcmp() zostanie zatrzymana, jeśli napotka NUL na którymkolwiek z dwóch łańcuchów. (w tym przypadku łańcuchy są różne) Strncmp() zatrzymałoby się i zwróciło zero ("łańcuchy są równe w pierwszych N znakach")

Jednym z możliwych sposobów użycia stncmp() jest parsowanie opcji, aż do signifacant część, np

if (!strncmp("-st", argv[xx], 3)) {} 

, który wróci do zera dla "-string" lub "-state" lub "-st0", ale nie dla "-sadistic".

2

Poza trikami, aby sprawdzić, czy początek ciągu pasuje do danych wejściowych, strncmp przydaje się tylko wtedy, gdy nie masz 100% pewności, że ciąg znaków jest zakończony null przed końcem przydzielonego miejsca.

Więc jeśli miał Ustalony rozmiar bufora, który wziął swoje dane wprowadzone przez użytkownika przy użyciu można użyć:

strncmp(user_input, "status", sizeof(user_input)) 

Dlatego też zapewnienie, że porównanie nie ma wycieków.

Jednak w tym przypadku musisz zachować ostrożność, ponieważ jeśli twoja wartość user_input nie zakończyła się na wartość null, to naprawdę sprawdzi, czy user_input odpowiada początkowi statusu.

Lepszym sposobem może być powiedzieć:

if (user_input[sizeof(user_input) - 1] != '\0') { 
    // handle it, since it is _not_ equal to your string 
    // unless filling the buffer is valid 
} 
else if (strcmp(user_input, "status")) { ... } 
+0

user_input [sizeof (user_input) -1]! = '\ 0 ", w przeciwnym razie jesteś poza tablicą user_input –

+0

Whoops. – jmh