Qué tipo de #include (“” o ) al escribir una biblioteca en C/C++

9 minutos de lectura

Avatar de usuario de Phil Rosenberg
phil rosenberg

Estoy escribiendo una biblioteca en C++. La biblioteca tiene múltiples encabezados y archivos cpp y debe ser multiplataforma (Windows Visual Studio y Linux gcc). Cuando se construyen, la biblioteca y los encabezados se instalan en un directorio del sistema en algún lugar, donde otro código puede encontrarlos en la misma máquina (por ejemplo, /usr/local en un sistema Linux).

Si uno de mis encabezados necesita #incluir uno de mis otros encabezados, ¿debería usar corchetes angulares o comillas?

Siento que los corchetes angulares son lo que se debe usar una vez que se instala la biblioteca para que se verifiquen los directorios del sistema, pero cuando construyo la biblioteca necesito usar comillas para que se verifiquen los directorios locales y no elija una versión desactualizada. de los directorios del sistema.

Soy consciente de lo que son las diferentes versiones de #include <filename> y #include “filename” significar. Estoy preguntando cuál es apropiado y por qué, para la situación de escribir una biblioteca.

  • Sería una buena idea hacer que el escenario que requiere la “instalación” de la biblioteca sea opcional u omitirlo por completo. Windows ni siquiera tiene un concepto de instalación de biblioteca para ningún idioma en particular e incluso en Linux, el desarrollo generalmente se realiza sin tocar esas rutas predefinidas.

    – usuario7860670

    21 de noviembre de 2018 a las 11:03

  • Esta pregunta no es un duplicado, ya que no se trata de la diferencia técnica entre usar corchetes angulares y comillas dobles, sino sobre cuál usar al escribir una biblioteca (y hay al menos dos razones para no usar corchetes angulares en este caso, uno de los cuales ya fue proporcionado por el autor de la pregunta).

    – Código falso mono Rashid

    18 de agosto de 2020 a las 17:14

Cuando usa corchetes angularesel compilador busca el archivo en la lista de rutas de inclusión. Cuando usas comillas doblesprimero busca en el directorio actual (es decir, el directorio donde está el módulo que se está compilando) y solo entonces buscará en la lista de rutas de inclusión.

Entonces, por convención, usa los corchetes angulares para las inclusiones estándar y las comillas dobles para todo lo demás. Esto asegura que en el caso (no recomendado) de tener una cabecera local con el mismo nombre que una cabecera estándar, se elegirá la correcta en cada caso.

Consulte la siguiente respuesta SO para obtener más detalles

¿Diferencia entre corchetes angulares y comillas dobles ” ” al incluir archivos de encabezado en C++?

  • Esto asegura que en el caso (no recomendado) de tener una cabecera local con el mismo nombre que una cabecera estándar, se elegirá la correcta en cada caso. Pero con el enfoque de paréntesis angulares, #include <mylib/float.h> es menos ambiguo para el lector que #include "float.h" (donde float.h es un encabezado de biblioteca estándar de C).

    – Émile Cormier

    29 de abril de 2022 a las 23:31

Avatar de usuario de Emile Cormier
Emilio Cormier

Actualmente me enfrento a la misma decisión con una biblioteca en la que estoy trabajando, que está destinada a ser consumida por proyectos distintos al mío. Ninguna de las otras respuestas aquí aborda el sentido práctico de forma citada vs angular de inclusiones dentro de las propias bibliotecas, pero simplemente explica las diferencias técnicas entre las dos formas.

Parece haber una división sobre qué formulario de inclusión es mejor para las fuentes/encabezados de la biblioteca, incluidos los encabezados de la misma biblioteca. No creo que esté calificado para dar la respuesta definitiva. Lo que voy a hacer aquí es intentar resumir los pros y los contras de cada enfoque lo mejor que pueda, y vincular a algunos recursos que encontré en línea.

Las pautas básicas de C++ [1] tiene esto que decir bajo SF.12:

Los creadores de bibliotecas deben poner sus encabezados en una carpeta y hacer que los clientes incluyan esos archivos usando la ruta relativa #include <some_library/common.h>

Las ventajas de la forma angular que se enumeran a continuación suponen que los encabezados de una biblioteca se colocan en una carpeta “raíz” con el nombre de la biblioteca (odio cuando las bibliotecas no hacen eso).

Desafortunadamente, las Directrices principales de C++ no establecen explícitamente lo que deben hacer los creadores de bibliotecas al incluir sus propios encabezados dentro de sus propios archivos fuente/de encabezado de biblioteca. Sin embargo, un colaborador me aclaró amablemente en [4] que en su ejemplo:

#include "foo_utils/utils.h"
    // A file locally relative to foo.cpp in the same project, use the "" form

el término proyecto también se aplica a las bibliotecas. Ese colaborador también aclaró que “localmente relativo” se dejó en manos del lector para que los casos de #include "../../include/somelib/foo.hpp" podría interpretarse como no relativo localmente, de modo que #include <somelib/foo.hpp> puede usarse en su lugar.

Tenga en cuenta que las Directrices básicas de C++, en coautoría con Stroustrup, contradicen un poco la Regla AV 33 de los estándares de codificación JSF anteriores de Stroutrup. [2] cuando se trata de la preferida #include forma. Tal vez cambió de opinión con respecto a esto.

Ventajas de la #include <somelib/foo.hpp> acercarse:

  • Como se discutió en [3]le permite al usuario proporcionar sus propios archivos de encabezado de biblioteca parcheados colocándolos en un directorio que se buscó anteriormente, a través de -I o -isystem indicadores del compilador. La aplicación de parches a través de este método probablemente solo sea viable para bibliotecas de solo encabezado.
  • Si uno de los encabezados de su biblioteca tiene el mismo nombre que uno de los encabezados del sistema, entonces es menos confuso a cuál se refiere. p.ej: #include <somelib/float.h> contra #include "float.h"donde float.h resulta ser un encabezado de biblioteca estándar de C.
  • Evita confiar en el comportamiento incoherente de la forma citada entre los compiladores y cumple con la regla AV 33 de los estándares de codificación JSF de Stroutrup. [2]. Esto puede no ser un problema si la biblioteca no pretende ser portátil entre muchos compiladores.
  • Evita la fealdad cuando el archivo incluido vive en un directorio principal o hermano del archivo incluido. P.ej #include <somelib/foo/bar.hpp> contra #include "../foo/bar.hpp". Considere también el caso en el que los archivos fuente y de encabezado viven en diferentes directorios del proyecto de biblioteca: #include <somelib/foo/bar.hpp> contra #include "../include/foo/bar.hpp" cuando se incluye desde un archivo cpp de biblioteca.
  • Cuando se usa en los archivos cpp de la biblioteca, permite al usuario simplemente incrustar los archivos cpp de la biblioteca en el sistema de compilación de la aplicación y no tener que mantener la misma estructura de directorios relativa entre los archivos de encabezado y fuente de la biblioteca. Esto puede ser deseable si la biblioteca consta de solo uno (o unos pocos) archivos cpp y el proyecto de la aplicación no desea utilizar el método de compilación proporcionado por la biblioteca. Por ejemplo, un proyecto de aplicación usa bazel, pero la biblioteca solo proporciona una compilación de CMake.

Ventajas de la #include "foo.hpp" acercarse:

  • Deja en claro al lector que el archivo que se incluirá es parte del mismo “proyecto” que el archivo incluido.
  • Si un usuario tiene versiones de la biblioteca tanto instaladas localmente como instaladas en el sistema, puede evitar que el encabezado instalado en el sistema se incluya accidentalmente si el usuario no configuró la configuración adecuada. -I o -isystem banderas
  • Si un usuario principiante no sabe cómo configurar -I o -isystem marca correctamente para apuntar a una versión local de la biblioteca, simplemente pueden hacer #include "../dependencies/somelib/include/somelib/foo.hpp" (que encuentro terriblemente feo, tal vez irracionalmente).

Con base en la investigación anterior y en la amable ayuda del colaborador de las Pautas básicas de C++, ahora mi objetivo personal es adoptar la siguiente convención:

  • Cuando un archivo de encabezado de biblioteca incluye otro encabezado de la misma biblioteca: Utilice #include "foo.h", #include "bar/foo.hpp"o #include "../bar/foo.hpp"según la ubicación relativa del otro archivo de encabezado.
  • Cuando un archivo fuente de biblioteca (cpp) incluye uno de los encabezados propios de la biblioteca: use #include <somelib/foo.hpp> o #include <somelib/bar/foo.hpp>.

El primero deja en claro que quiero incluir un archivo de encabezado que se incluye con la misma biblioteca que el archivo que realiza la inclusión.

Este último hace posible que los archivos fuente de la biblioteca se compilen colocándolos directamente en el sistema de compilación de una aplicación, sin tener que mantener la misma estructura de directorio relativa entre los archivos fuente y de encabezado de la biblioteca. También evita la #include "../include/somelib/foo.hpp" fealdad a favor del limpiador #include <somelib/foo.hpp>.

Cuando los archivos fuente de mi biblioteca se compilan usando los scripts CMake de la biblioteca (para generar una biblioteca estática/compartida), los scripts CMake controlan el -I y -isystem banderas y, por lo tanto, puede garantizar que la ruta de encabezados de biblioteca correcta tendrá la máxima prioridad de búsqueda.


[1] https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rs-incform

[2] https://www.stroustrup.com/JSF-AV-rules.pdf

[3] https://lists.boost.org/Archives/boost//2008/09/142030.php

[4] https://github.com/isocpp/CppCoreGuidelines/pull/1596#issuecomment-1113901271

Si utiliza "..." el compilador buscará primero en el directorio local y luego en el directorio del sistema.

Si utiliza <...> el compilador buscará en el directorio del sistema.

Una biblioteca de usuario residirá normalmente junto con el programa. Entonces puedes usar "..."

En cualquier caso, puede agregar rutas de búsqueda adicionales utilizando el IDE o crear un archivo.

si los encabezados en su directorio de trabajo, debe usar ""
pero, si los encabezados en la ruta del sistema o dentro de su ruta de inclusión, debe usar <>.

¿Ha sido útil esta solución?