Vor kurzem (Januar 2016, falls die Frage lange genug andauert) hatten wir die Frage Sind die Zeichenfolgen in argv änderbar? .
Im Kommentarbereich zu dieser Antwort haben wir (@ 2501 und ich) darüber gestritten, ob es wirklich die Strings sind Zeichen (ein Beispielzeichen ist **argv
), das änderbar ist, oder die Zeiger auf die Zeichenfolgen (ein Beispielzeiger ist *argv
).
Das entsprechende Standardangebot stammt aus dem C11-Standardentwurf N1570, §5.1.2.2.1 / 2:
Die Parameter
argc
undargv
und die Strings, auf die dieargv
array soll durch das Programm veränderbar sein und deren Zuletzt gespeicherte Werte zwischen Programmstart und Programmbeendigung.
Also sind die Zeiger auf die Zeichenfolgen, auf die argv
modifizierbar zeigt?
Wie in der Frage angegeben, gibt der C11-Standard explizit an, dass die Variablen argc
und argv
sowie die Strings, auf die das Array argv
zeigt, änderbar sind. Ob diese Zeiger änderbar sind oder nicht, ist die Frage zur Hand. Der Standard scheint es nicht ausdrücklich auf die eine oder andere Art zu sagen.
Es gibt zwei wichtige Punkte, die bezüglich der Formulierung in der Norm zu beachten sind:
Wenn die Zeiger unveränderlich sein sollten, hätte der Standard klargestellt, dass main als int main(int argc, char *const argv[])
deklariert werden sollte, wie hacks erwähnt in einer anderen Antwort auf diese Frage.
Die Tatsache, dass nirgends im Standard const
in Verbindung mit argv
erwähnt wird, scheint absichtlich. Das heißt, das Fehlen von const
scheint nicht optional, sondern durch den Standard diktiert.
Der Standard ruft argv
konsistent als Array auf. Das Ändern eines Arrays bezieht sich auf das Ändern seiner Mitglieder. Daher scheint es offensichtlich, dass die Formulierung in der Norm sich auf die Änderung der Mitglieder im Array argv
bezieht, wenn angegeben wird, dass argv
modifizierbar ist.
Andererseits müssen Array -Parameter in C (basierend auf C11-Entwurf N1570, §6.7.6.3p7) "an 'qualified pointer to type'" . Also, der folgende Code,
%Vor% ist gültig C11, da x
und y
auf int *x
bzw. int *y
eingestellt sind. (Dies wird auch im C11-Entwurf N1570, §6.3.2.1p3, wiederholt: "... array ... wird in einen Ausdruck mit dem Typ 'Zeiger auf Typ' konvertiert, der auf das Anfangselement des Arrays zeigt. . ".)
Das Gleiche wäre natürlich nicht, wenn x
und y
als lokale oder globale Arrays deklariert wären, keine Funktionsparameter.
Was den Sprachanwaltsberuf betrifft, würde ich sagen, dass der Standard dies nicht auf die eine oder andere Weise festlegt, obwohl dies auch bedeutet, dass die Zeiger modifizierbar sein sollten. Also als Antwort auf OP: beide .
In der Praxis gibt es eine sehr lange Tradition, die Zeiger im Array argv
modifizierbar zu machen. Viele Bibliotheken verfügen über Initialisierungsfunktionen, die einen Zeiger auf argc
und einen Zeiger auf das Array argv
verwenden, und einige von ihnen ändern die Zeiger im Array argv
(durch Entfernen von für die Bibliothek spezifischen Optionen); zum Beispiel GTK + gtk_init()
und MPI_Init()
(obwohl mindestens OpenMPI ausdrücklich angibt, dass sie nicht untersucht oder modifiziert werden). Suchen Sie nach der Parameterdeklaration (int *argc, char ***argv)
; Der einzige Grund dafür - angenommen, die Absicht besteht darin, aus main()
mit (&argc, &argv)
aufgerufen zu werden - besteht darin, die Zeiger zu ändern, die bibliotheksspezifischen Befehlszeilenparameter aus den Befehlszeilenparametern zu analysieren und zu entfernen Sowohl argc
als auch die Zeiger in argv
nach Bedarf.
(Ich habe ursprünglich angegeben, dass die Funktion getopt()
in POSIX auf getopt()
, und nur wenn die Umgebungsvariable POSIXLY_CORRECT
nicht gesetzt ist.Beide GNU getopt_long()
und BSD getopt_long()
modifizieren die Zeiger, es sei denn POSIXLY_CORRECT
ist gesetzt, aber Sie sind viel jünger und weniger verbreitet im Vergleich zu getopt()
.)
Im Unix-Land wurde es als "portabel" angesehen, den Inhalt der Strings zu ändern, auf die argv[]
array verweist, und die modifizierten Strings in der Prozessliste sichtbar machen . Ein Beispiel dafür, wie nützlich das ist, ist das daemontools-Paket von DJB, readproctitle . (Beachten Sie, dass die Zeichenfolgen vor Ort geändert werden müssen und nicht erweitert werden können, damit die Änderungen in der Prozessliste sichtbar sind.)
All dies weist auf eine sehr lange Tradition hin, im Grunde fast seit der Geburt von C als Programmiersprache und definitiv vor der Standardisierung von C, der Behandlung von argc
, argv
, den Zeigern im argv
-Array, und den Inhalt der Zeichenfolgen, auf die diese Zeiger zeigen, als veränderbar.
Da die Absicht des C-Standards nicht darin besteht, ein neues Verhalten zu definieren, sondern existierendes Verhalten über Implementierungen zu kodifizieren (um Portabilität und Zuverlässigkeit zu fördern), ist es sicher anzunehmen, dass es sich um eine unbeabsichtigte Auslassung des Standards handelte Schreiber, um die Zeiger im argv
-Array nicht explizit als modifizierbar zu spezifizieren. Alles andere würde die Tradition sprengen und ausdrücklich dem POSIX-Standard zuwiderlaufen (der auch die Portabilität systemübergreifend fördern und C-Funktionen erweitern soll, die nicht im ISO-C-Standard enthalten sind).
Tags und Links c pointers language-lawyer argv