Sind die Zeiger auf Strings in argv modifizierbar? [Duplikat]

8

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 und argv und die Strings, auf die die    argv 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?

    
Downvoter 30.01.2016, 19:13
quelle

2 Antworten

6

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:

  1. 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.

  2. 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() verändert nicht die tatsächlichen Zeiger, nur GNU 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).

    
Nominal Animal 31.01.2016, 01:26
quelle
1

Ob ein Zeiger veränderbar ist oder nicht, hängt von der Konstanz des Zeigers ab. Der Parameter argv wird als char *argv[] oder char **argv deklariert. Es hängt von der Umgebung ab, ob sie dies als char *const argv[] behandeln oder nicht (mir ist nichts bekannt).

    
haccks 30.01.2016 19:30
quelle

Tags und Links