Перейти к основному содержимому
  1. Rust/

Атрибуты и условная компиляция в Rust: #[cfg], #[inline], #[allow] и repr(C)

747 слов·4 минуты· loading · loading · · ·Rust-middle Черновик
О Rust - Эта статья часть цикла.
Статей прочитано 0/58
0%
📚 Введение и дополнительные материалы
🟢 Начальный уровень (Rust-basic)
Не прочитана
🔵 Средний уровень (Rust-middle)
42 Атрибуты и условная компиляция в Rust: #[cfg], #[inline], #[allow] и repr(C) (текущая)
Не прочитана

Введение
#

Атрибуты в Rust — это метаданные, которые передаются компилятору rustc для управления сборкой, оптимизациями, условной компиляцией и бинарным представлением данных.

Если в прошлых статьях мы уже встречали макроатрибуты при написании макросов в rust-procedural-macros или при разметке структур для C-ABI в rust-unsafe-and-ffi, то в этой статье мы системно разберем работу с атрибутами языка.


1. Анатомия атрибутов: внешние #[...] и внутренние #![...]
#

В Rust различают две категории атрибутов по их синтаксису и области применения:

  1. Внешние атрибуты (#[...]): относятся к элементу кода, расположенному непосредственно под ними (функция, структура, модуль, ветка перечисления).
  2. Внутренние атрибуты (#![...]): с восклицательным знаком относятся к контейнеру, внутри которого они объявлены (к текущему файлу, модулю или всему крейту).
#![allow(unused_imports)] // Внутренний атрибут: отключает предупреждение для ВСЕГО файла

#[allow(dead_code)] // Внешний атрибут: отключает предупреждение только для этой структуры
struct InternalConfig {
    id: u64,
}

2. Условная компиляция (#[cfg] и макрос cfg!)
#

Условная компиляция позволяет отсекать ненужные блоки кода до начала фазы оптимизаций и генерации машинных инструкций. Это незаменимо при написании кроссплатформенного кода под Linux, macOS и Windows.

Атрибут #[cfg(...)] поддерживает логические комбинаторы:

  • #[cfg(target_os = "linux")] — проверка операционной системы.
  • #[cfg(not(target_os = "windows"))] — логическое НЕ.
  • #[cfg(any(target_os = "linux", target_os = "macos"))] — логическое ИЛИ.
  • #[cfg(all(unix, target_arch = "x86_64"))] — логическое И.

Динамический макрос cfg!(...) позволяет проверять условия компиляции прямо внутри обычных ветвлений if-else.

Ниже представлен пошаговый пример работы с #[cfg] и макросом cfg!:

Условная компиляция #[cfg] и макрос cfg!
Шаг 1/2
 1// Шаг 1: Условная компиляция функций с помощью атрибута #[cfg]
 2
 3// Данная функция скомпилируется только на операционной системе Linux
 4#[cfg(target_os = "linux")]
 5fn get_os_family() -> &'static str {
 6    "Linux OS"
 7}
 8
 9// Данная функция скомпилируется только на операционной системе macOS (darwin)
10#[cfg(target_os = "macos")]
11fn get_os_family() -> &'static str {
12    "macOS (Darwin)"
13}
14
15// Данная функция скомпилируется только на операционной системе Windows
16#[cfg(target_os = "windows")]
17fn get_os_family() -> &'static str {
18    "Windows OS"
19}
20
21// Резервная реализация для всех остальных систем
22#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
23fn get_os_family() -> &'static str {
24    "Другая операционная система"
25}
26
27fn main() {
28    println!("Текущая операционная система: {}", get_os_family());
29}
30

1. Условная компиляция #[cfg]

  • Атрибут #[cfg(...)] исключает не удовлетворяющий условию код прямо во время парсинга на этапе компиляции.
  • Поддерживает логические операторы any(...), all(...) и not(...).

3. Оптимизации, линтеры и разметка памяти #[repr(C)]
#

Помимо условной компиляции, атрибуты управляют поведением компилятора и линтера:

  • #[inline] и #[inline(always)]: дают подсказку компилятору встроить тело функции непосредственно в точку вызова, исключая накладные расходы на вызов.
  • #[allow(...)], #[warn(...)], #[deny(...)]: настраивают уровни предупреждений встроенного линтера.
  • #[repr(C)]: запрещает Rust-оптимизатору переупорядочивать поля структуры и фиксирует бинарную разметку по стандарту C-ABI.

Изучите пошаговый пример применения #[inline], #[allow] и #[repr(C)] в блоке ниже:

Атрибуты lints, inline и #[repr(C)]
Шаг 1/2
 1// Шаг 1: Управление линтером и оптимизациями (#[allow], #[inline])
 2
 3// Подавляем предупреждения о неиспользуемом коде
 4#[allow(dead_code)]
 5struct UnusedConfig {
 6    debug_level: u32,
 7}
 8
 9// Принудительное встраивание тела функции компилятором
10#[inline(always)]
11fn fast_add(a: i32, b: i32) -> i32 {
12    a + b
13}
14
15fn main() {
16    let result = fast_add(10, 20);
17    println!("Результат быстрого сложения: {result}");
18}
19

1. Атрибуты lints и inline

  • #[allow(...)] подавляет выбранные предупреждения компилятора.
  • #[inline] и #[inline(always)] подсказывают компилятору встроить тело функции в точку вызова для ускорения выполнения.

Проверь свои знания!
#

Пройдите короткий тест по атрибутам и условной компиляции:

Статья прочитана
Пожалуйста, оцените насколько статья была вам полезна и понятна
Цикл статей
О Rust - Эта статья часть цикла.
Статей прочитано 0/58
0%
📚 Введение и дополнительные материалы
🟢 Начальный уровень (Rust-basic)
Не прочитана
🔵 Средний уровень (Rust-middle)
42 Атрибуты и условная компиляция в Rust: #[cfg], #[inline], #[allow] и repr(C) (текущая)
Не прочитана

Связанные статьи