Zgodnie z PO w pytaniu, standard C11 wyraźnie stwierdza, że zmienne argc
i argv
oraz ciągi wskazane przez tablicę argv
można modyfikować. Niezależnie od tego, czy te wskaźniki są modyfikowalne, czy nie, jest to pytanie. Standard nie wydaje się jednoznacznie określać tego w taki czy inny sposób.
Istnieją dwa kluczowe punkty, aby pamiętać o brzmienia w standardzie:
Jeśli wskaźniki miały być niezmienne, a średnia mógł jasno wymagając główny zostać zadeklarowana jako int main(int argc, char *const argv[])
, jako haccks mentioned w innej odpowiedzi na to pytanie.
Fakt, że nigdzie w standardzie nie jest const
wymieniony w związku z argv
, wydaje się celowy. Oznacza to, że brak parametru const
nie wydaje się opcjonalny, ale dyktowany przez standard.
Standardowo wywołuje argv
konsekwentnie tablicę. Modyfikowanie tablicy odwołuje się do modyfikowania jej członków. Dlatego wydaje się oczywiste, że sformułowanie w standardzie odnosi się do modyfikacji elementów w tablicy argv
, gdy stwierdza, że argv
jest modyfikowalne.
Z drugiej strony, tablica parametry w C (na podstawie C11 projekcie N1570, §6.7.6.3p7) „zostaną dostosowane do«wykwalifikowanego wskaźnik do typu»”. Zatem, poniższy kod,
int foo(int x[2], int y[2])
{
if (x[0] > y[0])
x = y;
return x[1];
}
jest ważny C11, ponieważ x
i y
są dostosowane do int *x
i int *y
odpowiednio. (Jest to również powtórzone w C11 draft N1570, §6.3.2.1p3: "... array ...jest konwertowane na wyrażenie o typie "wskaźnik do typu", który wskazuje na początkowy element tablicy ... ".) Oczywiście, to samo by nie było, gdyby x
i y
zostały zadeklarowane jako tablice lokalne lub globalne, a nie parametry funkcji.
Jeśli chodzi o język-lawyerism idzie, powiedziałbym, że norma nie stanie, w jakim taki czy inny sposób, choć implikuje kursory zbyt powinny być modyfikowane. Zatem, jako odpowiedź do OP: zarówno.
W praktyce istnieje bardzo długa tradycja, że wskaźniki w tablicy argv
można modyfikować. Wiele bibliotek ma funkcje inicjalizacyjne, które pobierają wskaźnik do argc
i wskaźnik do tablicy argv
, a niektóre z nich modyfikują wskaźniki w tablicy argv
(usuwając opcje specyficzne dla biblioteki); na przykład GTK+ gtk_init()
i MPI_Init()
(chociaż przynajmniej OpenMPI wyraźnie stwierdza, że nie sprawdza ani nie modyfikuje ich). Wyszukaj deklarację parametru (int *argc, char ***argv)
; jedynym powodem tego - zakładając, że intencją jest wywoływanie z main()
przy użyciu (&argc, &argv)
- jest modyfikowanie wskaźników, analizowanie i usuwanie specyficznych dla biblioteki parametrów wiersza poleceń z parametrów wiersza polecenia, modyfikujących zarówno argc
i wskaźniki w argv
w razie potrzeby.
(początkowo stwierdził, że zakład w POSIX getopt()
opiera się na wskaźnikach jest modyfikowalny - funkcja sięga roku 1980, przyjęta przez większość Unix i ujednolicone w POSIX.2 w 1997 roku - ale to jest nieprawidłowe, jak Jonathan Leffler podkreślił w komentarzu: POSIX getopt()
nie zmienia rzeczywiste wskaźniki; tylko GNU getopt()
robi, i to tylko wtedy, gdy zmienna POSIXLY_CORRECT
środowisko nie jest ustawiony Zarówno GNU getopt_long()
i BSD getopt_long()
modyfikować wskazówek chyba POSIXLY_CORRECT
jest ustawiony. , ale są znacznie młodsze i mniej rozpowszechnione w porównaniu do getopt()
.)
W krainie Uniksa uznano za "przenośne" modyfikowanie zawartości łańcuchów wskazanych przez argv[]
tablicę, i modyfikowanie łańcuchów widocznych na liście procesów. Jednym z przykładów tego, jak to było przydatne, jest pakiet daemontools DJB, readproctitle. (Zauważ, że ciągi musiałyby zostać zmodyfikowane na miejscu i nie można ich rozszerzyć, aby zmiany były widoczne na liście procesów.)
Wszystko to wskazuje na bardzo długą tradycję, prawie od narodzin C jako język programowania, i zdecydowanie poprzedzający standaryzację C, traktowania argc
, argv
, wskaźników w macierzy argv
i zawartości łańcuchów wskazanych przez te wskaźniki, jako modyfikowalne.
Ponieważ celem normy C nie jest definiowanie nowego zachowania, ale kodyfikowanie istniejącego zachowania we wszystkich implementacjach (w celu zwiększenia przenośności i niezawodności itd.), Można bezpiecznie założyć, że było to niezamierzone opuszczenie części strony. Standardowe programy piszące nie określają bezpośrednio wskaźników w tablicy argv
jako modyfikowalne. Wszystko inne złamałoby tradycję i byłoby wyraźnie sprzeczne ze standardem POSIX (który ma również na celu promowanie przenoszenia w różnych systemach i rozszerza funkcje C nie zawarte w standardzie ISO C).
Ponieważ 'argv' jest modyfikowalne, a' argv' zawiera wskaźniki, o których mówisz, tak. –
@SimonShine Ale jeśli 'argv' jest modyfikowalny, czy nie oznacza to, że tylko' argv = ... 'może być zrobione i niekoniecznie' * argv = ... '? – Downvoter
Ponieważ jedną z właściwych deklaracji funkcji 'main' jest' int main (int argc, char * argv []) 'wygląda na to, że parametr' argv' jest tablicą wskaźników 'char *', a nie 'char const * argv [] "wskaźniki. Zatem ciągi powinny być modyfikowalne. – nsilent22