Warum können Arrays in C nicht als Funktionsargumente übergeben werden?

12

Nach diesem Kommentar habe ich versucht zu googeln, warum, aber mein google-fu ist fehlgeschlagen.

Kommentar vom Link:

[...] Wichtig ist jedoch, dass Arrays und Zeiger in C unterschiedliche Dinge sind.

Angenommen, Sie verwenden keine Compilererweiterungen, können Sie im Allgemeinen kein Array selbst an eine Funktion übergeben, aber Sie können einen Zeiger übergeben und einen Zeiger indizieren, als wäre er ein Array.

Sie beschweren sich effektiv darüber, dass Zeiger keine Länge haben. Sie sollten sich darüber beschweren, dass Arrays nicht als Funktionsargumente übergeben werden können oder dass Arrays implizit zu Zeigern degradiert werden.

Florian Margaine
quelle
Ich bin nicht sicher, ob es die Antwort ist, aber ein Teil des Typs eines Arrays ist seine Größe. Ich glaube, Sie müssten eine Funktion für jede Größe definieren, die Sie akzeptieren möchten.
Clcto
Meinst du als Funktionszeiger ? Bitte klären Sie die Frage.
user949300
2
@ user949300 Nein, aus dem Kontext des Kommentars geht es ziemlich klar hervor. Sie können ein Array nicht an eine Funktion übergeben, da es zu einem Zeiger wird, und er möchte wissen, warum dies der Fall ist.
Doval
@DocBrown rlemon hat hierfür eine Änderung vorgeschlagen.
Florian Margaine

Antworten:

18

Meine erste Vermutung für den Grund war einfach aus Gründen der Leistung und der Speicherersparnis sowie der Einfachheit der Compiler-Implementierung (insbesondere für die Art von Computern zu der Zeit, als C erfunden wurde). Das Übergeben von großen Arrays "nach Wert" schien eine enorme Auswirkung auf den Stack zu haben. Für jeden Funktionsaufruf ist ein vollständiger Array-Kopiervorgang erforderlich, und wahrscheinlich muss der Compiler intelligenter sein, um den korrekten Assembly-Code auszugeben (obwohl der letzte Punkt fraglich ist). . Es wäre auch schwieriger, dynamisch zugewiesene Arrays auf dieselbe Weise wie statisch zugewiesene Arrays zu behandeln (unter dem Gesichtspunkt der Syntax der Sprache).

BEARBEITEN: Nachdem ich einige Teile dieses Links gelesen habe , denke ich, dass der wahre Grund (und der Grund, warum Arrays in Strukturen als Werttypen behandelt werden, während es keine einzigen Arrays sind) die Abwärtskompatibilität zu Cs Vorgänger B ist . Hier ist das Zitat von Dennis Ritchie:

[...] Die Lösung stellte den entscheidenden Sprung in der Evolutionskette zwischen typenlosem BCPL und typisiertem C dar. Sie beseitigte die Materialisierung des Zeigers im Speicher und verursachte stattdessen die Erstellung des Zeigers, wenn der Arrayname in einem Ausdruck erwähnt wird. Die Regel, die im heutigen C überlebt, lautet, dass Werte des Array-Typs in Ausdrücken in Zeiger auf das erste der Objekte konvertiert werden, aus denen das Array besteht.

Diese Erfindung ermöglichte es dem meisten existierenden B-Code, trotz der zugrunde liegenden Verschiebung in der Semantik der Sprache weiterzuarbeiten. [..]

Doc Brown
quelle
5
A struct Foo { int array[N]; } kann als Wert übergeben werden. Und der letzte Teil der Behandlung dynamischer und statischer Zuordnungen scheint faul zu sein (ein Array im engeren Sinne enthält immer eine Größe, die einheitlichen Konzepte für Dinge wie die Array-Indizierung sind Zeiger, die mit dem Zerfall von Arrays zu Zeigern gekoppelt sind ).
@delnan: Ich denke, die hier angegebenen allgemeinen Prinzipien sind solide. Wenn Sie Ihr Array in eine Struktur einschließen, geben Sie natürlich Ihre Absicht an. Im Allgemeinen werden Sie fast immer als Referenz übergeben.
Robert Harvey
Ich finde auch den Kommentar, auf den im OP verwiesen wird, unnötig umständlich. Offensichtlich übergeben Sie einen Zeiger anstelle eines Arrays nach Wert. Gleichermaßen gilt jedoch, dass Sie ein Array effektiv als Referenz übergeben. Wenn der Einwand ist, dass es keine Länge gibt, ist es einfach genug, das auch zu bestehen.
Robert Harvey
@RobertHarvey Das ist immer noch eine Asymmetrie im Typsystem: Alles wird als Wert übergeben, außer Array-Typen (auch wenn Arrays, die Teil eines Strukturtyps sind, als Wert übergeben werden), und es wird sogar genau dieselbe Notation verwendet (beide am Aufrufstandort) und in der Funktionssignatur).
@delnan: Warum ist das relevant, außer dass du es dir merken musst?
Robert Harvey
9

Ein PDP-Minicomputer mit nur 8 kB Speicher kann keinen sehr großen Stapel zuordnen. Auf einer solchen Maschine muss man also beim Design (oder der Entwicklung) einer Sprache vorsichtig sein, um zu minimieren, was für die erwartete Verwendung gemeinsamer Unterprogrammaufrufe auf dem Stack gespeichert werden muss. C wird heute noch verwendet, um extrem speicherbeschränkte (einige kB) eingebettete Systeme zu programmieren, daher ist der Kompromiss normalerweise ein guter.

Bei einer Prozessorarchitektur mit nur sehr wenigen Registern kann durch häufiges Übergeben eines Arrays nach Zeiger und nicht nach Wert ein Register als Subroutinen-Aufrufoptimierung verwendet werden.

hotpaw2
quelle
2
Ich habe einige Karten, die 256 Bytes RAM für die Daten und 2K EEPROM für den Code haben. Sie möchten dort keine Kopie eines Arrays erstellen.
Jerry Jeremiah