web-dev-qa-db-fra.com

Pourquoi utiliserait-on #include_next dans un projet?

Pour citer l'iOS Documentation sur les en-têtes Wrapper :

#include_next ne fait pas de distinction entre <fichier> et l'inclusion de "fichier", ni ne vérifie que le fichier que vous spécifiez porte le même nom que le fichier actuel. Il recherche simplement le fichier nommé, en commençant par le répertoire dans le chemin de recherche après celui où le fichier actuel a été trouvé.

L'utilisation de `#include_next 'peut entraîner une grande confusion. Nous recommandons de l'utiliser uniquement lorsqu'il n'y a pas d'autre alternative. En particulier, il ne doit pas être utilisé dans les en-têtes appartenant à un programme spécifique; il ne doit être utilisé que pour effectuer des corrections globales dans le sens des correctifs inclus.

Donc, deux questions, qu'est-ce que #include_next, et pourquoi auriez-vous besoin de l'utiliser?

49
CodaFi

Il est utilisé si vous souhaitez remplacer un en-tête par défaut par une de vos propres créations, par exemple, supposons que vous souhaitiez remplacer "stdlib.h". Vous créeriez un fichier appelé stdlib.h dans votre projet, qui serait inclus à la place de l'en-tête par défaut.

#include_next est utilisé si vous souhaitez ajouter des éléments à stdlib.h plutôt que de le remplacer entièrement. Vous créez un nouveau fichier appelé stdlib.h contenant:

#include_next "stdlib.h"
int mystdlibfunc();

Et le compilateur n'inclura pas votre stdlib.h à nouveau de manière récursive, comme ce serait le cas avec un simple #include, mais continuerait plutôt dans d'autres répertoires pour un fichier nommé "stdlib.h".

66
Hampus Nilsson

C'est pratique si vous prenez en charge plusieurs versions de quelque chose. Par exemple, j'écris du code qui prend en charge PostgreSQL 9.4 et 9.6. Un certain nombre de modifications API internes existent, principalement de nouveaux arguments pour les fonctions existantes.

En-têtes de compatibilité et fonctions d'encapsuleur

Je pourrais écrire des en-têtes de compatibilité avec static inline les fonctions de wrapper avec de nouveaux noms pour tout, essentiellement une API de wrapper, où j'utilise le nom de wrapper partout dans mon code. Dire something_compat.h avec:

#include "something.h"

static inline something*
get_something_compat(int thingid, bool missing_ok)
{
    assert(!missing_ok);
    return get_something(thingid);
}

mais c'est moche de disperser _compat ou n'importe quel suffixe partout.

En-tête d'emballage

Au lieu de cela, je peux insérer un en-tête de compatibilité dans le chemin d'inclusion lors de la construction par rapport à l'ancienne version, par exemple compat94/something.h:

 #include_next "something.h"

 #define get_something(thingid, missing_ok) \
 ( \
     assert(!missing_ok), \
     get_something(thingid) \
 )

donc le reste du code peut simplement utiliser la signature 9.6. Lors de la construction avec 9.4, nous préfixerons -Icompat94 au chemin de recherche d'en-tête.

Des précautions sont nécessaires pour éviter plusieurs évaluations, mais si vous utilisez #include_next cela ne vous dérange pas de vous fier à gcc. Dans ce cas, vous pouvez également utiliser expressions de déclaration .

Cette approche est pratique lorsque la nouvelle version est la cible "principale", mais une compatibilité descendante pour une ancienne version est souhaitée pour une période de temps limitée. Donc, vous dépréciez progressivement les anciennes versions et essayez de garder votre code propre en référence à la version actuelle.

Alternatives

Ou soyez une personne sensée, utilisez C++ et utilisez des fonctions surchargées et des fonctions de modèle en ligne: p

8
Craig Ringer