In der Programmiersprache C wird bei der Übergabe einer Struktur an eine Funktion by value eine vollständige Kopie der Struktur im temporären Speicherbereich erstellt (in der Regel auf dem Stack der Funktion). Das bedeutet, dass Änderungen innerhalb der Funktion das Originalexemplar der Struktur außerhalb der Funktion nicht beeinflussen.
Wenn Sie große Strukturen by value übergeben, stoßen Sie auf Zeit- und Speicherkosten aufgrund der Notwendigkeit, alle Mitglieder der Struktur zu kopieren. Daher ist es gängige Praxis, einen Zeiger auf die Struktur zu übergeben:
#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // Ändert nur die lokale Kopie } void modify_by_pointer(struct Data *d) { d->flag = 20; // Ändert das Original } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }
Vorteile der Übergabe per Zeiger:
Nachteile der Übergabe by value:
Was passiert, wenn eine Funktion eine Struktur by value zurückgibt? Welche Risiken gibt es?
Antwort:
In C ist es möglich, eine Struktur by value aus einer Funktion zurückzugeben, zum Beispiel:
struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // eine Kopie wird zurückgegeben }
Das Hauptproblem ist die Leistung: Eine Kopie der Struktur wird erstellt und zurückgegeben. Darüber hinaus kann bei einer fehlerhaften Rückgabe der Adresse einer lokalen Variablen die Struktur auf ungültigen Speicher zeigen:
struct Point* bad() { struct Point p = {1, 2}; return &p; // Fehler: Rückgabe der Adresse einer lokalen Variablen }
Geschichte
In eingebetteten Geräten mit geringem Stack übergab der Entwickler eine große Struktur (1 KB) by value, was zu einem Stack Overflow und sporadischen Systemausfällen führte. Ermittlungen zeigten, dass das Kopieren jeder Struktur zu einem Speicherengpass auf dem Stack bei tiefer Verschachtelung von Aufrufen führte.
Geschichte
In einem Unternehmensserversystem gab der Programmierer einen Zeiger auf eine lokale Struktur zurück, was im Code zu Zugriffen auf "hängende" Zeiger nach dem Verlassen der Funktion führte. Dies führte zu einem kritischen Segfault in der Produktion mit seltener Reproduzierbarkeit.
Geschichte
In einem Open-Source-Projekt fiel die Leistung drastisch ab, nachdem auf eine Funktion umgestiegen wurde, die eine komplexe Struktur mit internen Arrays by value zurückgab. Der Profiler stellte die Zeitkosten des Prozessors für unnötige wiederholte Kopieroperationen von Strukturen fest.