Понимание заголовков и включение

Я пытаюсь понять, как на самом деле несколько определений включаемых файлов взаимодействуют, а иногда и сталкиваются. Так что у меня есть пользовательский заголовочный файл file.hгде некоторые функции объявлены в #include guard, Пример:

#ifndef FILE_Ariew7OGJknw00
#define FILE_Ariew7OGJknw00

#include <stdlib.h>  //assume minimal

//interfaces of functions

#endif

Теперь у меня есть несколько вопросов.

1. С #include <stdlib.h> уже включен в шапку file.hМне не нужно включать его в мой file.c, Так как file.c включает в себя file.h который включает в себя stdlib.h, Однако, когда я включаю <stdlib.h> после file.h в моем .c, он все еще работает правильно. Почему это так? Подобно:

#include <stdio.h>
#include "file.h"
#inlcude <stdlib.h> 
//code

2. И что будет, если я сделаю:

#include <stdio.h>
#include <stdlib.h>
#inlcude "file.h" 
//code

На самом деле ничего, но почему бы и нет file.h определение пропущено (или это?) на основе охраны, так как библиотека stdlib уже включен.

И наконец, более общий вопрос: почему предохранители #include используются более широко, чем #pragma once хотя последний имеет несколько преимуществ, таких как:

• меньше кода
• предотвращение столкновений имен (т.е. FILE_Ariew7OGJknw00)
• улучшение скорости компиляции

2 ответа

Решение

Однако, когда я включаю после file.h в мой.c, он все еще работает должным образом. Почему это так?

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

почему определение file.h не пропущено (или нет?) из-за защиты, поскольку библиотека уже объявлена.

Включаемый охранник не проверяет, есть ли заголовки или включены или нет. Это не волнует / не знает, что внутри.

Препроцессор просто проверяет, включен ли макрос include guard FILE_Ariew7OGJknw00 определяется или нет. Если определено, оно пропускается. В противном случае он вставляется в ваш файл союса, куда вы его включили.

Почему защитники #include более широко используются, чем #pragma, хотя последний имеет несколько преимуществ

Это нестандартно. Это делает ваш код менее переносимым.


Не рекомендуется включать другие заголовочные файлы в заголовочный файл без необходимости. На практике вы не увидите многократных проблем с включением, так как они будут работать, как ожидается, благодаря включенным защитникам. Могут быть законные случаи, когда вам нужно включить другие заголовки. Например, если у вас есть такой заголовок:

/* header.h */

#ifndef MY_HEADER_H
#define MY_HEADER_H

#include<stdio.h>

struct my_struct {
   size_t len;
   char *s;
};

void my func(void);
void my_blah(int);

#endif

Тогда становится необходимым включить <stdio.h> получить size_t определение. Если вы этого не сделаете, файл souce, содержащий этот заголовок, должен будет включать <stdio.h>, Но заголовок должен работать сам по себе, не заставляя его знать все зависимости.

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

1. Стандарт языка требует, чтобы стандартные заголовки могли быть включены несколько раз без проблем. Это не говорит точно, как это работает, но включать охранников, конечно, один из способов.

3. Одна проблема с #pragma once в том, что это нестандартно. Комитет по стандартам не хочет точно определять, как он должен работать на всех возможных файловых системах, для всех возможных операционных систем. Если у вас есть несколько сетевых подключений из неизвестных источников и несколько жестко связанных файлов, может быть очень трудно определить, какие файлы совпадают.

В Windows и Linux он работает со всеми основными компиляторами. В других системах мы не знаем.

Другие вопросы по тегам