He leído que hay algo de optimización del compilador cuando se usa #pragma once
que puede resultar en una compilación más rápida. Reconozco que no es estándar y, por lo tanto, podría plantear un problema de compatibilidad multiplataforma.
¿Es esto algo que es compatible con la mayoría de los compiladores modernos en plataformas que no son de Windows (gcc)?
Quiero evitar problemas de compilación de la plataforma, pero también quiero evitar el trabajo adicional de los guardias alternativos:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
¿Debería Preocuparme? ¿Debo gastar más energía mental en esto?
c++
include-guards
Ryan Emerle
fuente
fuente
#pragma once
parece evitar algunos problemas de vista de clase en VS 2008. Estoy en el proceso de deshacerme de incluir guardias y reemplazarlos#pragma once
por esta razón.Respuestas:
El uso
#pragma once
debería funcionar en cualquier compilador moderno, pero no veo ninguna razón para no usar un#ifndef
protector de inclusión estándar . Funciona bien La única advertencia es que GCC no era compatible#pragma once
antes de la versión 3.4 .También descubrí que, al menos en GCC, reconoce el
#ifndef
protector de inclusión estándar y lo optimiza , por lo que no debería ser mucho más lento que#pragma once
.fuente
#pragma once
generalmente es más rápido porque el archivo no se está procesando previamente.ifndef/define/endif
requiere preprocesamiento de todos modos, porque después de este bloque puede tener algo compilable (en teoría)#ifndef FOO_BAR_H
, normalmente, para un archivo como "foo_bar.h". Si luego cambia el nombre de este archivo, ¿debería ajustar los protectores de inclusión en consecuencia para que sean consistentes con esta convención? Además, si tiene dos foo_bar.h distintos en dos lugares diferentes en su árbol de códigos, debe pensar en dos símbolos diferentes para cada uno. La respuesta corta es usar#pragma once
y si realmente necesita compilar en un entorno que no lo admite, continúe y agregue protectores de inclusión para ese entorno.#pragma once
tiene un inconveniente (aparte de no ser estándar) y es que si tiene el mismo archivo en diferentes ubicaciones (lo tenemos porque nuestro sistema de compilación copia archivos), entonces el compilador pensará que son archivos diferentes.fuente
#ifdef
valor macro también puede diferir.Yo deseo
#pragma once
(o algo así) haber estado en el estándar. Los guardias de inclusión no son un gran problema (pero parecen ser un poco difíciles de explicar a las personas que aprenden el idioma), pero parece una molestia menor que podría haberse evitado.De hecho, dado que el 99.98% del tiempo, el
#pragma once
comportamiento es el comportamiento deseado, hubiera sido bueno si el compilador manejara automáticamente la inclusión múltiple de un encabezado, con un#pragma
o algo para permitir la doble inclusión.Pero tenemos lo que tenemos (excepto que es posible que no tenga
#pragma once
).fuente
#import
directiva estándar .No conozco ningún beneficio de rendimiento, pero ciertamente funciona. Lo uso en todos mis proyectos de C ++ (siempre que esté usando el compilador de MS). Me parece más efectivo que usar
Hace el mismo trabajo y no llena el preprocesador con macros adicionales.
GCC admite
#pragma once
oficialmente a partir de la versión 3.4 .fuente
GCC admite
#pragma once
desde 3.4, consulte http://en.wikipedia.org/wiki/Pragma_once para obtener más compatibilidad con el compilador.La gran ventaja que veo al usar
#pragma once
en lugar de incluir guardias es evitar errores de copiar / pegar.Seamos realistas: la mayoría de nosotros apenas iniciamos un nuevo archivo de encabezado desde cero, sino que simplemente copiamos uno existente y lo modificamos según nuestras necesidades. Es mucho más fácil crear una plantilla de trabajo usando en
#pragma once
lugar de incluir guardias. Cuanto menos tenga que modificar la plantilla, es menos probable que encuentre errores. Tener la misma protección de inclusión en diferentes archivos conduce a errores extraños del compilador y lleva algún tiempo descubrir qué salió mal.TL; DR:
#pragma once
es más fácil de usar.fuente
Lo uso y estoy contento con él, ya que tengo que escribir mucho menos para hacer un nuevo encabezado. Me funcionó bien en tres plataformas: Windows, Mac y Linux.
No tengo ninguna información de rendimiento, pero creo que la diferencia entre #pragma y el protector de inclusión no será nada comparado con la lentitud de analizar la gramática de C ++. Ese es el verdadero problema. Intente compilar la misma cantidad de archivos y líneas con un compilador de C #, por ejemplo, para ver la diferencia.
Al final, usar la guardia o el pragma no importará en absoluto.
fuente
Utilizando '
#pragma once
' podría no tener ningún efecto (no es compatible en todas partes, aunque es cada vez más compatible), por lo que debe usar el código de compilación condicional de todos modos, en cuyo caso, ¿por qué molestarse con '#pragma once
'? El compilador probablemente lo optimiza de todos modos. Sin embargo, depende de las plataformas de destino. Si todos tus objetivos lo admiten, entonces adelante y úsalo, pero debería ser una decisión consciente porque todo el infierno se desatará si solo usas el pragma y luego lo transfieres a un compilador que no lo admite.fuente
El beneficio de rendimiento es no tener que volver a abrir el archivo una vez que se ha leído el #pragma una vez. Con los guardias, el compilador tiene que abrir el archivo (que puede ser costoso a tiempo) para obtener la información de que no debe incluir su contenido nuevamente.
Esa es la teoría solo porque algunos compiladores no abrirán automáticamente archivos que no tienen ningún código de lectura, para cada unidad de compilación.
De todos modos, no es el caso para todos los compiladores, por lo que idealmente #pragma debe evitarse una vez para el código multiplataforma si no es estándar / no tiene una definición y efecto estandarizados. Sin embargo, prácticamente, es realmente mejor que los guardias.
Al final, la mejor sugerencia que puede obtener para asegurarse de tener la mejor velocidad de su compilador sin tener que verificar el comportamiento de cada compilador en este caso, es usar pragma una vez y guardias.
De esa manera, obtienes lo mejor de ambos (multiplataforma y velocidad de compilación de ayuda).
Como es más largo de escribir, yo personalmente uso una herramienta para ayudar a generar todo eso de una manera muy fácil (Visual Assist X).
fuente
pragma
después delifndef
? ¿Hay algún beneficio?No siempre.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52566 tiene un buen ejemplo de dos archivos destinados a ser incluidos, pero erróneamente se pensó que eran idénticos debido a marcas de tiempo y contenido idénticos (nombre de archivo no idéntico) .
fuente
#pragma once
no es estándar, por lo que cualquier cosa que un compilador decida hacer es "correcta". Por supuesto, entonces podemos comenzar a hablar sobre lo que se "espera" y lo que es "útil".Usar gcc 3.4 y 4.1 en árboles muy grandes (a veces haciendo uso de distcc ), todavía tengo que ver alguna velocidad al usar #pragma una vez en lugar de, o en combinación con guardias de inclusión estándar.
Realmente no veo cómo vale la pena confundir las versiones anteriores de gcc, o incluso otros compiladores, ya que no hay ahorros reales. No he intentado todos los diversos de-linters, pero estoy dispuesto a apostar que confundirá a muchos de ellos.
También deseo que se haya adoptado desde el principio, pero puedo ver el argumento "¿Por qué necesitamos eso cuando ifndef funciona perfectamente bien?". Dadas las muchas esquinas y complejidades oscuras de C, incluir guardias es una de las cosas más fáciles de explicar. Si tiene un pequeño conocimiento de cómo funciona el preprocesador, deberían explicarse por sí mismos.
Sin embargo, si observa una aceleración significativa, actualice su pregunta.
fuente
Hoy en día, los guardias de inclusión de la vieja escuela son tan rápidos como un #pragma una vez. Incluso si el compilador no los trata especialmente, se detendrá cuando vea #ifndef WHATEVER y WHATEVER está definido. Abrir un archivo es muy barato hoy. Incluso si hubiera una mejora, sería del orden de milisegundos.
Simplemente no uso #pragma una vez, ya que no tiene ningún beneficio. Para evitar chocar con otros guardias de inclusión, uso algo como: CI_APP_MODULE_FILE_H -> CI = Company Initials; APP = nombre de la aplicación; el resto se explica por sí mismo.
fuente
La principal diferencia es que el compilador tuvo que abrir el archivo de encabezado para leer el protector de inclusión. En comparación, pragma una vez hace que el compilador realice un seguimiento del archivo y no haga ningún archivo IO cuando se encuentra con otra inclusión para el mismo archivo. Si bien eso puede parecer insignificante, puede ampliarse fácilmente con grandes proyectos, especialmente aquellos sin un buen encabezado que incluyen disciplinas.
Dicho esto, en la actualidad los compiladores (incluido el CCG) son lo suficientemente inteligentes como para incluir a los guardias como pragma una vez. es decir, no abren el archivo y evitan la penalización de IO del archivo.
En los compiladores que no admiten pragma, he visto implementaciones manuales que son un poco engorrosas.
Personalmente, me gusta el enfoque de #pragma una vez, ya que evita la molestia de nombrar colisiones y posibles errores tipográficos. También es un código más elegante en comparación. Dicho esto, para el código portátil, no debería doler tener ambos a menos que el compilador se queje de ello.
fuente
#pragma once
ha existido!Si usamos msvc o Qt (hasta Qt 4.5), desde GCC (hasta 3.4), ambos soportan msvc
#pragma once
, no puedo ver ninguna razón para no usarlo#pragma once
.El nombre del archivo fuente generalmente es el mismo nombre de clase igual, y sabemos que a veces necesitamos refactorizar , para cambiar el nombre de la clase, también tuvimos que cambiar el nombre
#include XXXX
, así que creo que el mantenimiento manual#include xxxxx
no es un trabajo inteligente. incluso con la extensión Visual Assist X, mantener el "xxxx" no es un trabajo necesario.fuente
Nota adicional para las personas que piensan que siempre se desea una inclusión automática de archivos de encabezado por única vez: construyo generadores de código utilizando la inclusión doble o múltiple de archivos de encabezado desde hace décadas. Especialmente para la generación de stubs de biblioteca de protocolos, me resulta muy cómodo tener un generador de código extremadamente portátil y potente sin herramientas e idiomas adicionales. No soy el único desarrollador que usa este esquema como muestran los blogs X-Macros . Esto no sería posible sin la protección automática que falta.
fuente
X-Macro
función, pero no es el uso principal de include, ¿no debería ser al revés como header unguard / # pragma multi si nos quedamos con DRY?