1. Wie werden Strukturen im Gedächtnis gespeichert?int main() { Student(in) stu.id = 123456; strcpy(stu.name,"feizhufeifei"); stu.math = 90; stu.PE = 80; printf("Student:%p\r\n",&stu); printf("stu.ID:%p\r\n",&stu.ID); printf("stu.name:%p\r\n",&stu.name); printf("stu.math:%p\r\n",&stu.math); gebe 0 zurück; } Die Druckergebnisse sind wie folgt: //Die Adresse der Struktur Student:0xffffcbb0 //Die Adresse des ersten Mitglieds der Struktur stu.ID:0xffffcbb0 //Offsetadresse + 0 stu.name:0xffffcbb4//Offset-Adresse + 4 stu.math:0xffffcbd4 //Offset-Adresse + 24 Wir können sehen, dass die Adresse der Struktur mit der Adresse des ersten Mitglieds der Struktur übereinstimmt. Aus diesem Grund haben wir in „Weigern Sie sich, das Rad neu zu erfinden! So portieren und verwenden Sie die allgemeine verknüpfte Liste des Linux-Kernels (mit vollständiger Codeimplementierung)“ erwähnt, warum die Struktur „list_head“ an erster Stelle in der Struktur stehen sollte. Wenn Sie es nicht ganz verstehen, schauen Sie sich diese beiden Beispiele an:
Wir können sehen, dass die Membervariablen in der Struktur tatsächlich als Offset-Adressen im Speicher gespeichert sind. Das heißt, die Adresse der Struktur A + die Offset-Adresse der Mitgliedsvariable = die Startadresse der Strukturmitgliedsvariable. Daher können wir anhand der Startadresse der Strukturvariablen und der Offsetadresse der Membervariablen auch auf die Adresse der Struktur A schließen. 2. container_of-Makro#define offsetof(TYP, MITGLIED) ((Größe_t) &((TYP*)0)->MITGLIED) #define container_of(ptr, Typ, Mitglied) ({ \ const Typ von (((Typ *)0)->Mitglied)*__mptr = (ptr); \ (Typ *)((char *)__mptr - Offset von (Typ, Mitglied)); }) ??Schauen wir uns zunächst die drei Parameter an. ptr ist der Zeiger auf die Membervariable, type bezieht sich auf den Typ der Struktur und member ist der Name der Membervariable. Die Funktion des Makros „container_of“ besteht darin, die Adresse einer Strukturvariablen über die Adresse einer Mitgliedsvariablen in der Struktur, den Variablennamen und den Strukturtyp zu finden. Ein hier verwendeter Trick besteht darin, die Compilertechnologie zu verwenden, bei der zuerst der Offset des Strukturmitglieds in der Struktur ermittelt wird und dann basierend auf der Adresse der Mitgliedsvariablen die Adresse der Hauptstrukturvariablen ermittelt wird. Es folgt eine detaillierte Analyse jedes Teils. 3. Art vonSchauen wir uns zunächst typeof an, das verwendet wird, um den Typ einer Variablen zurückzugeben. Dies ist eine erweiterte Funktion des GCC-Compilers, was bedeutet, dass typeof vom Compiler abhängig ist. Es wird weder von der C-Sprachspezifikation gefordert, noch ist es Teil eines Standards. int main() { : Int a = 5; //Definieren Sie hier eine Variable b vom gleichen Typ wie a Typ von (a) b = 6; printf("%d,%d\r\n",a,b);//5 6 gebe 0 zurück; } 4. (((Typ *)0)->Mitglied)((TYPE *)0) konvertiert 0 in einen Strukturzeiger vom Typ type. Mit anderen Worten, der Compiler denkt, die Struktur beginne am Anfang des Programmsegments, also bei 0. Wenn sie bei Adresse 0 beginnt, ist die Adresse der Membervariablen, die wir erhalten, direkt gleich der Offsetadresse der Membervariablen. (((Typ *)0)->Mitglied) bezieht sich auf das MEMBER-Mitglied in der Struktur. Typdefinitionsstruktur Student{ Int-ID; Zeichenname[30]; int-Mathematik; }Student; int main() { //Hier wird die Struktur zwangsweise in die Adresse 0 konvertiert und dann die Adresse des Namens gedruckt. printf("%d\r\n",&((Student *)0)->Name);//4 gebe 0 zurück; } 5. const typeof(((Typ * )0) ->Mitglied)*__mptr = (ptr); Dieser Code bedeutet, dass mit Warum verwenden Sie nicht einfach 6. offsetof(Typ, Mitglied))
size_t ist in der Standard-C-Bibliothek definiert und wird auf 32-Bit-Architekturen im Allgemeinen wie folgt definiert:
Auf 64-Bit-Architekturen wird es wie folgt definiert:
Wie Sie der Definition entnehmen können, ist size_t eine nicht negative Zahl. Daher wird size_t normalerweise zum Zählen verwendet (da zum Zählen kein negativer Bereich erforderlich ist):
Um das Programm portabler zu machen, verwendet der Kernel 7. (Typ *)((Zeichen *)__mptr - Offset von (Typ, Mitglied)) Dieser Satz bedeutet, 8. Beispiele#define offsetof(TYP, MITGLIED) ((size_t) &((TYP *)0)->MITGLIED) #define container_of(ptr, Typ, Mitglied) ({ \ const typeof( ((Typ *)0)->Mitglied ) *__mptr = (ptr); \ (Typ *)( (Zeichen *)__mptr - Offset von (Typ, Mitglied) );}) Typdefinitionsstruktur Student { Int-ID; Zeichenname[30]; int mathe; }Student; int main() { Student(in) Student *sptr = NULL; stu.id = 123456; strcpy(stu.name,"zhongyi"); stu.math = 90; sptr = container_of(&stu.id,Student,id); printf("sptr=%p\n",sptr); sptr = container_of(&stu.name,Student,name); printf("sptr=%p\n",sptr); sptr = container_of(&stu.math,Student,id); printf("sptr=%p\n",sptr); gebe 0 zurück; } Die Ergebnisse sind wie folgt:
Makro-Erweiterung kann es klarer machen int main() { Student(in) Student *sptr = NULL; stu.id = 123456; strcpy(stu.name,"zhongyi"); stu.math = 90; //Erweitern und ersetzen Sie sptr = ({ const unsigned char *__mptr = (&stu.id); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->id) );}); printf("sptr=%p\n",sptr); //Erweitern und ersetzen Sie sptr = ({ const unsigned char *__mptr = (&stu.name); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->name) );}); printf("sptr=%p\n",sptr); //Erweitern und ersetzen Sie sptr = ({ const unsigned int *__mptr = (&stu.math); (Student *)( (char *)__mptr - ((size_t) &((Student *)0)->math) );}); printf("sptr=%p\n",sptr); gebe 0 zurück; } Dies ist das Ende dieses Artikels mit der detaillierten Erklärung des Container_Of-Makros im Linux-Kernel. Weitere Informationen zum Container_Of-Makro im Linux-Kernel finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: Praktisches MySQL + PostgreSQL Batch-Insert-Update insertOrUpdate
>>: Einführung in die Verwendung von this in HTML-Tags
Lösung für die Ausnahmen 1449 und 1045 bei der Ve...
Das Schreiben von XHTML erfordert eine saubere HTM...
In diesem Artikel wird der spezifische Code zum I...
Für eine Website ist dies die grundlegendste Funkt...
Klicken Sie hier, um zum Abschnitt „HTML-Tutorial“...
Details zur Sicherheitsanfälligkeit VSFTP ist ein...
Heutzutage werden Registerkarten häufig im Webdes...
1. Verwenden Sie den folgenden Befehl, um das SSH...
Inhaltsverzeichnis Einführung Herunterladen und i...
Gerade HTML-Anfänger stehen häufig vor dem Problem...
Das Umschreibmodul ist das Modul ngx_http_rewrite...
Vorwort Nginx (ausgesprochen „Engine X“) ist ein ...
Supervisor ist ein sehr gutes Daemon-Verwaltungst...
In diesem Artikel wird das Deep-Learning-Framewor...
Bei der getrennten Entwicklung von Front-End und ...