Verwenden von struct Alignment und Padding in C

Jinku Hu 12 Oktober 2023
  1. Verstehen Sie die Grundlagen von Alignment und Padding in C
  2. Verwenden der Member-Reordering-Technik, um Platz in Objekten in C zu sparen
Verwenden von struct Alignment und Padding in C

In diesem Artikel werden verschiedene Methoden zur Verwendung von struct-Ausrichtung und -Padding in C erläutert.

Verstehen Sie die Grundlagen von Alignment und Padding in C

Alle Objekte im Speicher werden als primäre Datentypen dargestellt, wie: char, short, int, long, pointer usw. Diese Datentypen haben ihre entsprechende Größe im Speicher. Auf den meisten modernen 64-Bit-Desktop-Prozessoren sind die Größen 1 Byte für ein char, 2 Byte für ein short, 4 Byte für ein int, 8 Byte für einen pointer und so weiter. Beachten Sie, dass dies keine garantierten Größen sind (außer für char), aber man kann die Größe des Objekts mit dem sizeof-Operator abrufen. Nun ist Alignment die Methode, die Compiler verwenden, um Variablen im Speicher zu platzieren, was bedeutet, dass jeder grundlegende Datentyp an der Adresse gespeichert wird, die durch die entsprechende Größe teilbar ist.

Normalerweise wird das Alignment genutzt, um schneller und effizienter auf Datenobjekte zugreifen zu können. Die Ausrichtung zwingt kontinuierlich deklarierte unterschiedliche Datentypen dazu, einen gewissen Abstand zwischen ihren Adressen einzuhalten. Wenn wir nämlich, wie im folgenden Beispiel gezeigt, eine Struktur st1 mit einem Zeiger und einem char deklarieren, nimmt sie insgesamt 16 Bytes ein. Wohlgemerkt, ein einzelner Zeiger benötigt 8 Bytes und ein char ein Byte, also würde man denken, dass die st1-Struktur 9 Bytes belegen muss. Es verhält sich aber so, als ob alle Mitglieder auf die Größe des größten Mitglieds ausgerichtet sind (also 8 Bytes). st2 struct demonstriert eine ähnliche Struktur, die die gleiche Menge an Speicher belegt, außer dass sie ein Array mit 7 char Mitgliedern hat.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  typedef struct {
    char *p;
    char c2;
  } st1;

  typedef struct {
    char *p;
    char c2;
    char padding[7];
  } st2;

  printf("sizeof st1 = %zu\n", sizeof(st1));
  printf("sizeof st2 = %zu\n", sizeof(st2));

  exit(EXIT_SUCCESS);
}

Ausgabe:

sizeof st1 = 16
sizeof st2 = 16

Verwenden der Member-Reordering-Technik, um Platz in Objekten in C zu sparen

Das vorherige Beispiel zeigt, dass es eine gewisse Speicherverschwendung gibt, wenn Strukturen verschiedene Typen enthalten und die Ausrichtungsgrenzen nicht ausfüllen. Es gibt jedoch einige Fälle, in denen es möglich ist, Strukturmitglieder neu zu ordnen und so zusätzlichen Platz zu sparen.

Der nächste Beispielcode definiert foo1 struct, das das größte Mitglied (char *) in der Mitte hat und foo2 mit dem gleichen Mitglied wie das erste. Die Größen dieser beiden Objekte sind unterschiedlich - 24 Byte und 16 Byte. Das hat mit der Reihenfolge der Datenmitglieder zu tun. In der Struktur foo1 muss p an der Adresse ausgerichtet werden, die durch 8 teilbar ist, so dass das int und das short davor insgesamt 8 Bytes belegen und die beiden char * s danach ebenfalls die 8 Bytes belegen. Wenn wir jedoch p an die erste Stelle verschieben, quetschen sich die folgenden Glieder in die 8 Bytes und die Ausrichtungsregel ist ebenfalls erfüllt. Somit beträgt die Größe von foo2 insgesamt 16 Bytes und es wird als gepacktes struct bezeichnet. Beachten Sie, dass der gcc-Compiler den speziellen __attribute__ ((packed))-Spezifizierer hat, der sogar ungeordnete struct-Mitglieder dazu zwingen kann, gepackt zu werden.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  typedef struct {
    int n1;
    short s1;
    char *p;
    char c1;
    char c2;
  } foo1;

  typedef struct {
    char *p;
    int n1;
    short s1;
    char c1;
    char c2;
  } foo2;

  typedef struct {
    int n1;
    short s1;
    char *p;
    char c1;
    char c2;
  } __attribute__((packed)) foo3;

  printf("sizeof foo1 = %zu\n", sizeof(foo1));
  printf("sizeof foo2 = %zu\n", sizeof(foo2));
  printf("sizeof foo3 = %zu\n", sizeof(foo3));

  exit(EXIT_SUCCESS);
}

Ausgabe:

sizeof foo1 = 24
sizeof foo2 = 16
sizeof foo3 = 16
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C Struct