7

Почему используются #ifndef и #define в заголовочных файлах C++?

25

Я заметил, что в начале заголовочных файлов часто встречается следующий код:

#ifndef HEADERFILE_H
#define HEADERFILE_H

А в конце файла находится:

#endif

Какова цель этого?

4 ответ(ов)

0

В приведённом вами примере используется директива препроцессора #ifndef, которая проверяет, был ли ранее определён указанный токен. Если токен не определён, то компилятор включает код между #ifndef и соответствующим #else (если он есть) или #endif. Это позволяет избежать повторного включения одного и того же кода, что особенно актуально для файлов заголовков.

Вот пример, который вы привели:

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

В данном случае #ifndef _INCL_GUARD проверяет, определён ли токен _INCL_GUARD. Если он не определён, то код между этой директивой и #define _INCL_GUARD будет выполнен, и токен будет определён. При следующем включении этого файла заголовка #ifndef обнаружит, что _INCL_GUARD уже определён, и пропустит содержимое, тем самым предотвращая повторное включение. Это техника, известная как «guard» или «include guard», и она используется для обеспечения идемпотентности заголовочных файлов.

0

Этот код предотвращает многократное включение одного и того же заголовочного файла.

#ifndef __COMMON_H__
#define __COMMON_H__
// Содержимое заголовочного файла
#endif

Допустим, вы включили этот заголовочный файл в несколько других файлов. В первый раз, когда компилятор встречает __COMMON_H__, он не определен, поэтому заголовочный файл будет включен, и __COMMON_H__ будет определен.

При следующем включении этого заголовочного файла, __COMMON_H__ уже будет определен, и файл не будет включен снова. Это позволяет избежать ошибок, связанных с повторным определением.

0

Эти конструкции называются ifdef или охранными директивами (include guards).

Если вы пишете небольшую программу, может показаться, что они не нужны, но по мере роста проекта вы можете намеренно или случайно подключить один и тот же файл несколько раз, что может привести к предупреждению компилятора, как "переменная уже объявлена".

  • #ifndef проверяет, что HEADERFILE_H не объявлен.
  • #define объявит HEADERFILE_H, как только #ifndef станет истинным.
  • #endif определяет границы действия #ifndef, т.е. конец секции #ifndef.

Если переменная не объявлена, то есть #ifndef возвращает истину, тогда выполняется только часть кода между #ifndef и #endif, в противном случае — нет. Это предотвратит повторное объявление идентификаторов, перечислений, структур и т.д.

0

#ifndef проверяет, определён ли данный токен ранее в файле или в подключённом файле; если нет, то включается код между этой директивой и завершающей #else или #endif, если #else отсутствует. #ifndef часто используется для обеспечения идемпотентности заголовочных файлов, определяя токен после включения файла и проверяя, что токен не был установлен в верхней части этого файла.

Пример использования:

#ifndef ABOUTSCREEN_H
#define ABOUTSCREEN_H

#include <fcntl.h>
#include <unistd.h>

#define CHARGING_STATUS_FILE "/cable.2/state"

#define LED_ON "255"
#define LED_OFF "0"

namespace Ui
{
    class aboutScreen;
}

class aboutScreen : public QWidget
{
    Q_OBJECT

public:
    enum LedColors
    {
        OFF,
        RED,
        BLUE,
        GREEN,
        WHITE
    };

    explicit aboutScreen(QWidget *parent = 0, Ui::mainStackWidget *uiMainStackWidget = 0);
    ~aboutScreen();
    void init(void);
    void writeLedStatus(QString, QString);

public slots:
    void updateBatteryAndStorageStatus(void);

private slots:
    void on_backButton_pressed();
    void on_backButton_released();

private:
    Ui::mainStackWidget *uiMainStackWidget;
};

#endif // ABOUTSCREEN_H

В этом коде #ifndef ABOUTSCREEN_H предотвращает повторное включение определения класса aboutScreen, что может привести к конфликтам при компиляции. Если файл aboutScreen.h уже был включён, код между #ifndef и #endif игнорируется, что помогает избежать дублирования определений.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь