Dlaczego potrzebujemy argc, skoro na końcu argv zawsze występuje wartość null?

117

Wydaje się, że argv[argc]jest zawsze NULL, więc myślę, że możemy przeglądać listę argumentów bez argc. Zrobi to pojedyncza whilepętla.

Jeśli zawsze występuje NULLna końcu argv, dlaczego potrzebujemy argc?

StarPinkER
źródło
17
To prawdopodobnie kwestia wygody. Daje programiście łatwy sposób na wczesne wycofanie się, jeśli nie ma wystarczającej liczby argumentów, bez zapętlania. W przeciwnym razie na pewno posiadają funkcje zwane int argc(char *argv[])robi dokładnie to :-))
cnicutar
5
Żeby było jasne "\0", nie jest taki sam jak wskaźnik NULL ( 0jest odpowiednikiem NULL w C ++)
Mats Petersson
31
Dlaczego potrzebujemy, aby argv [argc] miało wartość NULL, jeśli mamy argc?
Ambroz Bizjak
7
Jak inaczej określiłbyś liczbę argumentów w stałym czasie?
avakar
4
Nie myśl, że tagi linux / unix są tutaj odpowiednie, ponieważ takie zachowanie powinno być prawdziwe dla wszystkich kompilatorów we wszystkich systemach operacyjnych.
Darrel Hoffman

Odpowiedzi:

106

Tak, argv[argc]==NULLjest gwarantowane. Zobacz C11 5.1.2.2.1 Uruchomienie programu ( wyróżnienie moje)

Jeżeli są zadeklarowane, parametry funkcji głównej muszą spełniać następujące ograniczenia:

Wartość argc nie jest ujemna. argv [argc] będzie pustym wskaźnikiem.

argcDlatego dostarczanie nie jest niezbędne, ale nadal jest przydatne. Między innymi pozwala na szybkie sprawdzenie, czy została podana poprawna liczba argumentów.

Edycja: pytanie zostało zmienione w celu uwzględnienia C ++. n3337 szkic 3.6.1 Mówi główna funkcja

2 ... argc będzie liczbą argumentów przekazanych do programu ze środowiska, w którym program jest uruchamiany. .... Wartość argc nie powinna być ujemna. Wartość argv [argc] powinna wynosić 0 .

simonc
źródło
36
I argcmoże być dość duże, ponieważ powłoka robi ekspansji (tak w jest rozszerzany przez powłokę przed z wykonywalny). W moim systemie mogę mieć kilkaset tysięcy. ls **execve/bin/lsargc
Basile Starynkevitch
To całkiem fajne, nigdy nie przyszło mi to do głowy, ponieważ zawsze uważałem za argcwystarczające, ale zdecydowanie mogę wymyślić sytuacje, w których ta gwarancja byłaby istotna, a nawet wymagana. +1
Thomas
6
@BasileStarynkevitch Czas zwykłego przechodzenia przez tablicę wartości wskaźnika jeden dodatkowy raz do NULL, aby uzyskać liczbę, jest niewielki w porównaniu z czasem spędzonym na generowaniu tablicy wskaźników, a nawet bardziej nieistotny w porównaniu z faktycznym użyciem wartości każdego argumentu w programie. A jeśli po prostu sprawdzisz, czy liczba argumentów jest większa niż N, to przechodzenie przez całą tablicę nie jest potrzebne. Mimo to w pełni się zgadzam, że to argcbyła i jest dobra rzecz.
hyde
43

Tak, argv[argc]na pewno będzie pustym wskaźnikiem. argcjest używany dla wygody.

Cytując oficjalne wyjaśnienie z C99 Rationale, zwróć uwagę na słowa redundant check :

Uzasadnienie dla normy międzynarodowej - języki programowania - C §5.1.2.2.1 Uruchomienie programu

Specyfikacja argci argvjako argumenty mainuznające rozległą wcześniejszą praktykę. argv[argc]musi być zerowym wskaźnikiem, aby zapewnić nadmiarowe sprawdzenie końca listy, również na podstawie powszechnej praktyki.

Yu Hao
źródło
19

Dzieje się tak ze względów historycznych i zgodności ze starym kodem. Początkowo nie było gwarancji, że będzie istniał wskaźnik zerowy jako ostatni element tablicy argv. Ale argc istniał zawsze .

zentrunix
źródło
... Co jest w pewnym sensie wstydem. Gdybyśmy to zrobili int main(char *argv[], int argc, ...), niektóre programy mogłyby po prostu pominąć ten element, argcponieważ go nie potrzebują. Wręcz przeciwnie (potrzeba, argcale nie argv) prawdopodobnie nigdy nie jest przydatna w prawdziwym programie.
hyde
@hyde: patrz komentarz powyżej Basile Starynkevitch
zentrunix
6

„Potrzebujemy” tego, bo wymagają tego różne standardy.

Możemy całkowicie zignorować wartość, ale ponieważ jest to pierwszy parametr programu main, musimy go mieć na liście parametrów. W C ++ (i prawdopodobnie niestandardowych dialektach C) możesz po prostu pominąć nazwę parametru, na przykład ten fragment kodu C ++ (łatwy do konwersji na C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

W standardowym C, z typowymi ustawieniami ostrzeżeń, nieużywany parametr generuje ostrzeżenie, które można naprawić za pomocą instrukcji, na przykład (void)argc;która powoduje użycie nazwy bez generowania żadnego kodu.

argcdobrze jest mieć, ponieważ w przeciwnym razie wiele programów musiałoby przejść przez parametry, aby uzyskać liczbę. Ponadto w wielu językach programowania z tablicami o długości nie ma żadnego argcparametru, jest tylko tablica z elementami.

hyde
źródło
Pytanie dotyczy zarówno C, jak i C ++. W języku C nazwa parametru jest wymagana.