Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Структуры в C (struct): определение, инициализация, передача в функции, указатели и битовые поля

Что такое структура?

Структура (struct) — пользовательский тип, объединяющий переменные разных типов под одним именем. Позволяет моделировать записи (records) — сущности с несколькими атрибутами.

Объявление и определение

// Тег структуры: struct Book
struct Book {
    char title[100];
    char author[50];
    int year;
    double price;
    bool available;
}; // точка с запятой обязательна!

// Переменные структуры
struct Book book1;           // неинициализирована
struct Book book2 = {        // инициализация списком (порядок полей!)
    "C Programming", "K&R", 1978, 45.99, true
};
struct Book book3 = {        // designated initializers (C99) — порядок не важен
    .title = "Modern C",
    .author = "Jens Gustedt",
    .year = 2020,
    .price = 59.99
};

Доступ к полям

Структуры и функции

Передача по значению (копия всей структуры)

void print_book(struct Book b) { // копируется вся структура!
    printf("%s by %s (%d), $%.2f\n", b.title, b.author, b.year, b.price);
}
// Вызов: print_book(book1);

Плюсы: простота, иммутабельность аргумента. Минусы: накладные расходы на копирование больших структур.

Передача по указателю (рекомендуется для больших структур)

void print_book_const(const struct Book *b) { // const — обещание не менять
    printf("%s by %s (%d), $%.2f\n", b->title, b->author, b->year, b->price);
}

void apply_discount(struct Book *b, double percent) {
    b->price *= (1.0 - percent / 100.0);
}
// Вызов: print_book_const(&book1); apply_discount(&book1, 10.0);

Указатели на структуры

struct Book *ptr = &book1;
ptr->year = 2025;        // удобнее, чем (*ptr).year
(*ptr).price = 30.0;     // тоже работает, но скобки обязательны

Массивы структур

struct Book library[100];
library[0] = (struct Book){"Book A", "Author A", 2020, 10.0, true}; // compound literal (C99)
library[1].title = "Book B";

Вложенные структуры

struct Date { int day, month, year; };

struct Employee {
    char name[50];
    struct Date birth_date;  // вложенная структура (по значению)
    struct Date *hire_date;  // указатель на структуру
};

struct Employee emp = {
    .name = "John",
    .birth_date = {15, 5, 1990}, // инициализация вложенной
    .hire_date = &(struct Date){1, 1, 2020} // compound literal для указателя
};

Самореференциальные структуры (для списков, деревьев)

struct Node {
    int data;
    struct Node *next; // указатель на ТОТ ЖЕ тип
};

struct Node *head = NULL;
head = malloc(sizeof(struct Node));
head->data = 42;
head->next = NULL;

typedef для удобства

// Обычный способ
typedef struct {
    char title[100];
    char author[50];
    int year;
} Book; // теперь можно: Book b;

// Или с тегом (для самореференциальных)
typedef struct Node Node;
struct Node {
    int data;
    Node *next; // используем typedef имя
};

Выравнивание и упаковка (padding/packing)

Компилятор выравнивает поля по границам их типов для быстрого доступа. Это создаёт «дырки» (padding).

struct Padded {
    char c;     // 1 байт
    // 3 байта padding
    int i;      // 4 байта (выровнено по 4)
    // 0 байт padding
    double d;   // 8 байт (выровнено по 8)
}; // размер: 24 байта (1+3+4+8+8? нет, 1+3+4+8=16, но double требует 8-байтовое выравнивание структуры -> 24)

struct Packed {
    char c;
    int i;
    double d;
} __attribute__((packed)); // GCC/Clang атрибут: без padding
// Размер: 1+4+8=13, но доступ к int/double может быть медленным или вызвать SIGBUS на некоторых архитектурах!

Правило: располагайте поля от больших к маленьким для минимизации padding:

struct Optimal {
    double d;   // 8 байт, offset 0
    int i;      // 4 байта, offset 8
    char c;     // 1 байт, offset 12
    // 3 байта padding до размера, кратного 8 (alignof(max field))
}; // размер: 16 байт

Битовые поля (Bit Fields)

Позволяют упаковать несколько флагов/маленьких значений в одно машинное слово.

struct Flags {
    unsigned int is_active : 1;   // 1 бит
    unsigned int is_dirty  : 1;
    unsigned int mode      : 3;   // 3 бита (0-7)
    unsigned int reserved  : 29;  // остаток 32-битного слова
}; // размер: 4 байта (обычно)

struct Flags f = {.is_active = 1, .mode = 5};
if (f.is_active) { ... }
f.mode = 3;

Ограничения:

Неполные типы (opaque pointers / forward declaration)

Скрытие реализации (инкапсуляция):

// api.h
struct Context; // неполный тип
typedef struct Context Context;

Context *ctx_create(void);
void ctx_do_work(Context *ctx);
void ctx_destroy(Context *ctx);

// api.c
#include "api.h"
struct Context { // полное определение только здесь
    int secret_data;
    void *handle;
};
Context *ctx_create() { ... }

Клиентский код видит только указатель Context*, не значащий внутренностей.

Пример: комплексная структура с функциями

typedef struct {
    double re, im;
} Complex;

Complex c_add(Complex a, Complex b) {
    return (Complex){a.re + b.re, a.im + b.im};
}

Complex c_mul(Complex a, Complex b) {
    return (Complex){
        a.re * b.re - a.im * b.im,
        a.re * b.im + a.im * b.re
    };
}

void c_print(Complex c) {
    printf("%.2f %s %.2fi\n", c.re, (c.im >= 0 ? "+" : ""), c.im);
}

Язык C

  1. Структуры C++ против классов: практическое руководство для разработчиков встроенных систем
  2. Семафоры в Nucleus RTOS: Утилитарные сервисы и структуры данных
  3. Рецензия: «Оцифровывайся или умирай» — блупринт для IoT-драйвенной трансформации
  4. Сохранение человечности в эпоху разрушительных технологий
  5. Революция в хранилищах данных: магнитные наноструктуры с мантиями невидимости нового поколения
  6. Топ-17 книг по программированию для прокачки навыков кодинга в 2021 году
  7. Структуры данных в Java: основные классы и Collections Framework
  8. typedef в C: создание псевдонимов типов, упрощение кода и отличия от #define
  9. Структуры данных в C++: массивы, структуры и эффективное программирование
  10. Структуры в C#: определение, особенности и отличия от классов