c++ - sintaxis - que es una macro en programacion
¿Cuál es la diferencia entre una macro y una constante en C++? (8)
define se puede redefinir, pero const será causa de error del compilador:
muestra: fuente: main.cpp
#define int_constance 4
#define int_constance 8 // ok, compiler will warning ( redefine macro)
const int a = 2;
const int a = 4; // redefine -> error
int main(int argc, char** argv)
{
std::cout << int_constance ; // if remove second #define line, output will be 8
return 0;
}
Me hicieron esta pregunta en una entrevista técnica:
¿Cuál es la diferencia entre una
const
y una macro en C ++?
Mi respuesta fue que una macro es una directiva de preprocesador y podría ser difícil depurar la aplicación si usa una macro ya que se reemplaza con la expresión constante antes de la compilación, mientras que una const
puede tener un identificador de tipo y es fácil de depurar.
¿Alguien podría señalar alguna otra diferencia y cuál debería preferirse?
EDITAR:
De la documentación de IBM para C ++:
Las siguientes son algunas diferencias entre
#define
y el calificador de tipoconst
:
La directiva
#define
se puede usar para crear un nombre para una constante numérica, de caracteres o de cadena, mientras que se puede declarar un objeto const de cualquier tipo.Un objeto const está sujeto a las reglas de alcance para las variables, mientras que una constante creada con
#define
no lo está. A diferencia de un objetoconst
, el valor de una macro no aparece en el código fuente intermedio utilizado por el compilador porque se expanden en línea. La expansión en línea hace que el valor de macro no esté disponible para el depurador.Una macro se puede utilizar en una expresión constante, como un límite de matriz, mientras que un objeto
const
no puede. (Creo que seguramente necesitamos usar macro para definirarray_size
.El compilador no comprueba una macro, incluidos los argumentos de macro.
(Publicado originalmente para static const vs #define - reproduciéndose aquí ya que esta pregunta parece tener más "impulso" ... Avísame si eso es inapropiado ...)
Pros y contras de todo, dependiendo del uso:
- consts
- Problemas de ámbito / identificador correctamente manejados bien
- Tipo fuerte, único, especificado por el usuario
- puede intentar "escribir" un
#define
ala#define S std::string("abc")
, pero la constante evita la construcción repetida de distintos temporarios en cada punto de uso
- puede intentar "escribir" un
- Complicaciones de una regla de definición
- Puede tomar la dirección, crear constantes referencias a ellos, etc.
- define
- alcance "global" / más propenso a usos conflictivos, que pueden producir problemas de compilación difíciles de resolver y resultados inesperados en tiempo de ejecución en lugar de mensajes de error sensatos; mitigar esto requiere:
- Los identificadores largos, oscuros y / o coordinados centralmente, y el acceso a ellos no pueden beneficiarse de la coincidencia implícita de los espacios de nombres utilizados / actuales / buscados por Koenig, alias de espacios de nombres, etc.
- el uso de todos los caracteres en mayúsculas generalmente se requiere y se reserva para las definiciones de preprocesador (una guía importante para el uso del preprocesador a escala empresarial para que sea manejable, y que las bibliotecas de terceros puedan seguir), cuya observación implica la migración de consts o enumeraciones existentes a definiciones implica un cambio en el uso de mayúsculas (y por lo tanto afecta el código del cliente). (Personalmente, escribo con mayúscula la primera letra de las enumeraciones pero no las constantes, por lo que me golpearían aquí de todos modos, tal vez sea el momento de repensar eso).
- es posible realizar más operaciones en tiempo de compilación: concatenación de cadenas de caracteres literales, creación de cadenas (tomando tamaño de las mismas)
- el inconveniente es que dado que
#define X "x"
y algo de uso del cliente ala"pre" X "post"
, estás en problemas si quieres o necesitas hacer de X una variable que se pueda cambiar en tiempo de ejecución en lugar de una constante, mientras que esa transición es más fácil desdeconst char*
oconst std::string
dado que ya obligan al usuario a incorporar operaciones de concatenación.
- el inconveniente es que dado que
- no se puede usar sizeof directamente en una constante numérica definida
- sin tipo (GCC no advierte si se compara con no firmado)
- es posible que algunas cadenas de compilador / vinculador / depurador no presenten el identificador, por lo que se verá reducido a mirar "números mágicos" (cadenas, lo que sea ...)
- no puedo tomar la dirección
- el valor sustituido no tiene que ser legal (o discreto) en el contexto donde se crea la # definición, ya que se evalúa en cada punto de uso, por lo que puede hacer referencia a objetos aún no declarados, depende de la "implementación" que no es necesario esté pre-incluido, cree "constantes" como
{ 1, 2 }
que pueden usarse para inicializar arrays, o#define MICROSECONDS *1E-6
etc. (¡ definitivamente no lo recomiendo!) - algunas cosas especiales como
__FILE__
y__LINE__
pueden incorporarse en la sustitución de macros
- alcance "global" / más propenso a usos conflictivos, que pueden producir problemas de compilación difíciles de resolver y resultados inesperados en tiempo de ejecución en lugar de mensajes de error sensatos; mitigar esto requiere:
- enums
- solo posible para valores enteros
- Problemas de ámbito / identificador correctamente manejados bien
- fuertemente tipado, pero con un tamaño int suficientemente firmado o sin firmar sobre el que no tiene control (en C ++ 03)
- no puedo tomar la dirección
- restricciones de uso más fuertes (p. ej., incrementando -
template <typename T> void f(T t) { cout << ++t; }
no compilará) - el tipo de cada constante se toma de la enumeración
template <typename T> void f(T)
, por lo que latemplate <typename T> void f(T)
obtiene una instanciación distinta cuando se pasa el mismo valor numérico de diferentes enumeraciones, todas las cuales son distintas de cualquier instanciación real de f (int). - incluso con typeof, no podemos esperar que numeric_limits proporcione información útil
- el nombre de la fuente de la enumeración puede aparecer en varios lugares en RTTI, mensajes del compilador, etc. - posiblemente útil, posiblemente ofuscado
Como regla general, uso consts y considero que son la opción más profesional para el uso general (aunque los demás tienen una simplicidad atractiva para este viejo programador perezoso).
Las macros como #define y const se utilizan en el lenguaje de programación C para definir constantes.
Veamos la diferencia entre #define y const:
#definir
-
#define
directiva#define
es una directiva de preprocesador. -
#define
solo puede definir constantes simples.
const
-
const
variableconst
es como una variable normal en el lenguaje C. -
const
puede definir constantes complejas también.
Para la diferencia completa: Diferencia entre #define y const en C
Las macros no respetan el alcance, y el nombre de una macro puede no estar disponible para un depurador simbólico. Dan Saks tiene un artículo bastante completo sobre los méritos relativos de las macros (ninguna), los objetos constantes y las constantes de enumeración. Al igual que Stephen Dewhurst , Saks prefiere las constantes de enumeración para los valores enteros, ya que no ocupan almacenamiento (más precisamente, las constantes de enumeración no tienen duración de almacenamiento ni vinculación).
Las macros y las constantes no son remotamente lo mismo, cada una es apropiada para las circunstancias y su respuesta solo rasca la superficie de la diferencia. Además, C ++ tiene dos tipos diferentes de constantes.
Una constante definida con el calificador const
es mejor pensada como una variable no modificable . Tiene todas las propiedades de una variable: tiene un tipo, tiene un tamaño, tiene vínculos, puede tomar su dirección. (El compilador podría optimizar algunas de estas propiedades si puede salirse con la suya: por ejemplo, las constantes cuya dirección nunca se usa no pueden ser emitidas en la imagen ejecutable. Pero esto es solo por la gracia de la regla de "como si". ) Lo único que no se puede hacer con un dato const
es cambiar su valor. Una constante definida con enum
es un poco diferente. Tiene un tipo y un tamaño, pero no tiene vínculos, no puede tomar su dirección y su tipo es único. Ambos se procesan durante la fase de traducción 7, por lo que no pueden ser más que un valor de lvalue o rvalue. (Lamento la jerga en la oración anterior, pero tendría que escribir varios párrafos de lo contrario).
Una macro tiene muchas menos restricciones: puede expandirse a cualquier secuencia de tokens, siempre que el programa general siga siendo un programa bien formado. No tiene ninguna de las propiedades de una variable. La aplicación de sizeof
o &
a una macro puede o no hacer algo útil, dependiendo de a qué se expande la macro. Las macros a veces se definen para expandirse a literales numéricos, y a veces se piensa que dichas macros son constantes, pero no lo son: "el compilador propiamente dicho" (es decir, la fase de traducción 7) las ve como literales numéricos .
Generalmente se considera una buena práctica, hoy en día, no usar una macro cuando una constante funcionará. Las macros no obedecen las mismas reglas de alcance que todos los demás identificadores, lo que puede ser confuso, y si usa una constante, le da más información a la fase de traducción 7 y, por lo tanto, también al depurador. Sin embargo, las macros le permiten hacer cosas que no se pueden hacer de otra manera, y si necesita hacer una de esas cosas, no debe dudar en usarlas. (Las macros que están reduciendo su peso, en este sentido, por lo general no solo se expanden a literales numéricos, aunque no lo voy a decir nunca).
EDITAR: Aquí hay un ejemplo de una macro haciendo algo interesante. No es de ninguna manera, forma o forma una constante. Puede que haya una manera de obtener el mismo efecto sin una macro (si conoces una que no involucre secuencias de cadenas, ¡me gustaría saberlo!) Pero creo que es una buena ilustración tanto del poder como del el peligro de las macros (para este último, considere lo que haría si se usara fuera de un contexto muy específico ...)
static double elapsed()
{ ... }
#define ELAPSED ''['' << std::fixed << std::setprecision(2) << elapsed() << "] "
// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
cout << ELAPSED << "reading file: " << *f << ''/n'';
process_file(*f);
}
Otra diferencia es que una variable const
tiene una memoria y puede ser referenciada por un puntero. Macro es solo el autocompletado que ocurrirá antes de la compilación, por lo tanto, el nombre se pierde durante la compilación.
También la macro puede ser algo más que una constante. Puede ser una expresión o cualquier cosa que sea sintácticamente correcta, incluso una definición completa de una función.
Las macros se utilizan para representar opciones de programación, por ejemplo, tamaño de pila; mientras que cosnt
se usa para representar las constantes del mundo real como el valor de Pi o e.
Una macro siempre tiene un tipo, por ejemplo, #define FIVE 5
es de tipo int.
Una ventaja para la variable const sobre la macro podría ser el uso de la memoria: con una macro, el valor puede tener que duplicarse en todos los lugares en que se utiliza; una variable const no se duplicará en la memoria. (pero no estoy seguro de esta diferencia)
Uno debería preferir const int sum = 1;
sobre #define sum 1
por varias razones:
Mecanismo basado en el alcance:
#define
s no respeta los ámbitos por lo que no hay manera de crear un espacio de nombres con alcance de clase. Mientras que las variables const se pueden clasificar en clases.
Evitando números mágicos extraños durante los errores de compilación:
Si está utilizando #define
estos son reemplazados por el preprocesador en el momento de la precompilación. Por lo tanto, si recibe un error durante la compilación, será confuso porque el mensaje de error no hará referencia al nombre de la macro sino al valor y aparecerá un valor repentino , y uno perdería mucho tiempo rastreando en el código.
Facilidad de depuración:
También por las mismas razones, mientras que la depuración #define
no proporcionaría ayuda realmente.
Para evitar ambas situaciones, const
será una mejor opción.