Yo era esta pregunta en una técnica de la entrevista:

¿Cuál es la diferencia entre un const y una macro en C++?

Mi respuesta fue que una macro es una directiva de preprocesador y podría ser difícil de depurar la aplicación si se utiliza una macro, ya que se sustituye por la expresión de la constante de antes de la compilación, mientras que un const puede tener un identificador de tipo, y es fácil de depurar.

Alguien podría señalar cualquier otra diferencia y que debe ser preferido?

EDICIÓN:

De la documentación de IBM para C++:

Las siguientes son algunas de las diferencias entre #define y la const tipo de calificador:

  1. La #define directiva puede ser utilizado para crear un nombre para una numérico, carácter o una cadena constante, mientras que un const objeto de cualquier tipo puede ser declarado.
  2. Una const objeto está sujeto a las reglas de ámbito para variables, mientras que una constante creada mediante #define no lo es. A diferencia de un const objeto, el valor de una macro no aparece en el intermedio de código fuente utilizado por el compilador como se expanden en línea. La línea de expansión hace que el valor de la macro no está disponible para el depurador.
  3. Una macro puede ser utilizado en una expresión constante, como una matriz obligado, mientras que un const objeto no puede. (Creo que sin duda necesita para utilizar macros para definir array_size.
  4. El compilador no tipo de verificación de una macro, incluyendo macro argumentos.
La regla de “Una macro puede ser utilizado en una expresión constante, como una matriz obligado, mientras que un objeto const no.” es sólo para C y no C++.

OriginalEl autor Amm Sokun | 2011-06-18

7 Comentarios

  1. 24

    Macros y constantes son ni remotamente la misma cosa, cada uno a veces es adecuado para las circunstancias, y su respuesta sólo arañazos en la superficie de la diferencia. También, C++ tiene dos tipos diferentes de constantes.

    Una constante definida con el const calificador está pensado como un inmodificable variable. Tiene todas las propiedades de una variable: tiene un tipo, que tiene un tamaño, tiene vinculación, usted puede tomar su dirección. (El compilador podría optimizar algunas de estas propiedades, si es que puede salirse con la suya: por ejemplo, las constantes cuya dirección no se usa nunca, puede que no obtenga emitido en la imagen ejecutable. Pero esto es sólo por la gracia de el como-si la regla.) La única cosa que no pueden hacer a un const dato es cambiar su valor. Una constante definida con enum es un poco diferente. Tiene un tipo y un tamaño, pero no tiene vinculación, usted no puede tomar su dirección, y su tipo es único. Ambos son procesados durante la traducción de la fase 7, por lo que no puede ser cualquier cosa, pero un lvalue o r-value. (Siento lo de la jerga en la frase anterior, pero tendría que escribir varios párrafos de lo contrario.)

    Una macro tiene menos restricciones: se puede ampliar a cualquier secuencia de tokens, siempre y cuando el programa general sigue siendo un bien formado programa. No tiene ninguna de las propiedades de una variable. La aplicación de sizeof o & a una macro puede o no puede hacer algo útil, dependiendo de lo que la macro se expande. Las Macros se define a veces para ampliar literales numéricos, y tal macros son a veces el pensamiento de como constantes, pero no lo son: “el compilador adecuado” (es decir, la traducción de la fase 7) ve como literales numéricos.

    Es generalmente considerado una buena práctica, hoy en día, no usar una macro cuando un constante va a hacer. Las Macros no obedecen a las mismas reglas de ámbito como todos los otros identificadores, que puede ser confuso, y si se utiliza una constante de dar más información a la traducción de la fase 7 y por lo tanto también para el depurador. Sin embargo, las macros le permiten hacer cosas que no se pueden hacer de otra manera, y si usted necesita para hacer una de esas cosas, no dudes en usarlos. (Macros que están tirando de su peso, en este sentido, por lo general no acaba de ampliar literales numéricos, aunque no voy a decir nunca.)

    EDICIÓN: he Aquí un ejemplo de una macro haciendo algo interesante. Es en ninguna manera, forma o forma constante. Bien puede ser una manera de conseguir el mismo efecto sin una macro (si usted sabe que no implica stringstreams, me gustaría oír hablar de eso!) pero creo que tiene una buena ilustración de tanto el poder y el peligro de macros (para el último, piense en lo que haría si se utiliza 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);
    }
    Puede usted dar por favor un ejemplo de una situación donde la macro necesita definitivamente para hacer las cosas.
    No puedo pensar en un short ejemplo. Una situación común es cuando usted necesita para montar un nivel superior de la construcción de muchas de las piezas de repetitivo: véase, por ejemplo, mxr.mozilla.org/mozilla-central/source/xpcom/glue/… — sin macros de las cosas que está haciendo allí sería mucho más tediosas y propensas a errores al escribir. (No deseo para sostener XPCOM como un buen ejemplo, sin embargo; lo que se ve es pensado como tejido de la cicatriz a través de una errónea decisión de diseño que se hizo hace mucho tiempo, ahora intratable para corregir.)
    Macro de la concatenación de cadenas característica es muy útil durante la depuración #define DEBUG(x) cout<<#x”=”<<x; Y su token pegar función con ## puede ser utiliza para crear nuevos identificadores.
    Actualizado mi respuesta con un ejemplo de una macro que hace algo pequeña pero no trivial para lograr de ninguna otra manera.

    OriginalEl autor zwol

  2. 12

    Uno debe preferir const int sum = 1; más de #define sum 1 para un número de razones:

    En Función Del Ámbito Del Mecanismo:

    #defines no respeto de los ámbitos de lo que no hay forma de crear una clase de ámbito de espacio de nombres. Mientras que las variables const puede aplicarse en las clases.

    Evitar Extraño mágico de los números durante la compilación errores:

    Si usted está usando #define esos son reemplazados por el pre-procesador en el momento de la precompilación Así que si usted recibe un error durante la compilación, va a ser confuso porque el mensaje de error no se refieren el nombre de la macro, pero el valor y aparecerá un repentino valor, y uno sería un desperdicio de mucho tiempo de seguimiento en el código.

    Facilidad de Depuración:

    También por los mismos motivos, mientras que la depuración de #define no proporcionaría ninguna ayuda realmente.

    Para evitar ambas situaciones anteriores const será una mejor opción.

    para resumir, const es preferido porque podemos controlar a su alcance y es fácil de depurar. Pero entonces la pregunta es ¿por qué prefieren constantes globales de más de macros
    Sokun: También, porque macros son evil en el sentido de que siempre producen efectos secundarios no deseados. Como para el uso de macros como named constants en C++ rara vez hay una necesidad de hacerlo, Usando Macros como constantes con nombre viene a través de la C.
    He llegado a través de los números de magia, pero mágica números deben ser realmente especial.

    OriginalEl autor Alok Save

  3. 2

    Otra diferencia es que la const variable tiene una memoria y puede ser referenciado por un puntero. Macro es el autocompletar que va a suceder antes de la compilación, de ahí el nombre se pierde durante la compilación.

    También macro puede ser más que sólo una constante. Puede ser soy de expresión o cualquier cosa que es sintácticamente correcta, incluso toda una definición de una función.

    Macros se utilizan para representar las decisiones de programación por ejemplo, el tamaño de la pila; mientras que cosnt es utilizado para representar el mundo real constantes como valor de Pi o e.

    +1 para que se establezca claramente que una macro también puede definir cualquier expresión o función. Un ejemplo divertido de esto es BOOST_FOREACH, que permite recorrer cada elemento de una secuencia en un lugar limpio, conciso.

    OriginalEl autor Xolve

  4. 2

    ( Publicado originalmente por static const vs #define – reproducir aquí esta pregunta parece tener más “momentum”… quiero saber si eso es inadecuado… )

    Pros y los contras de todo, dependiendo de su uso:

    • consts
      • correctamente ámbito /identificador de choque asuntos tratados muy bien
      • fuerte, único, usuario-tipo especificado
        • podría intentar “tipo” de un #define ala #define S std::string("abc"), pero la constante evita repitió la construcción de los distintos empleos temporales en cada punto de uso
      • Una Definición de la Regla de complicaciones
      • puede tomar la dirección, crear const referencias a ellos, etc.
    • define
      • “global” ámbito de aplicación /más propensos a un conflicto de usos, que puede producir difíciles de resolver compilación de temas e inesperado de tiempo de ejecución de los resultados más que sane mensajes de error; la mitigación de este, se requiere:
        • largo, oscuro y/o coordinadas centralmente identificadores, y el acceso a ellos no puedan beneficiarse de forma implícita la coincidencia de usa/actual/Koenig-miró-up de espacio de nombres, nombres de alias etc.
        • uso de todos los caracteres en mayúsculas es generalmente requerida y reservado para el preprocesador define (una importante guía para la empresa la escala de preprocesador de uso siguen siendo manejables, y que la 3ª parte de las bibliotecas puede esperarse que siga), la observación de lo que implica la migración de los actuales consts o enumeraciones que define implica un cambio en la capitalización (y por lo tanto afecta código de cliente). (Personalmente, me capitalizar la primera letra de las enumeraciones, pero no consts, así que me gustaría ser hit aquí de todos modos – tal vez el tiempo para repensar).
      • más tiempo de compilación operaciones posibles: string literal de concatenación, stringification (tomando el tamaño de la misma)
        • desventaja es que, dada #define X "x" y algunos de uso cliente ala "pre" X "post", estás en problemas si usted quiere o necesita hacer X un tiempo cambiante, variable en lugar de una constante, mientras que la transición es más fácil desde un const char* o const std::string dado que ya se fuerza al usuario a incorporar la concatenación de operaciones.
      • no puede usar sizeof directamente sobre definida una constante numérica
      • sin tipo (GCC no advertir si se compara con unsigned)
      • algunos compilador/enlazador/depurador de cadenas no puede presentar el identificador, por lo que podrá ser reducido a mirar “números mágicos” (cadenas, lo que sea…)
      • no puede tomar la dirección
      • el valor sustituido necesidad de no ser legal (o discreta) en el contexto donde el #define se crea, como se evalúa en cada punto de uso, por lo que se puede hacer referencia a que aún no se ha declarado objetos, dependen de la “aplicación” que no tienen que ser pre-incluido, crear “constantes” como { 1, 2 } que puede ser usado para inicializar las matrices, o #define MICROSECONDS *1E-6 etc. (definitivamente no recomendar este!)
      • algunas cosas especiales como __FILE__ y __LINE__ pueden ser incorporados en la sustitución de macros
    • las enumeraciones
      • sólo es posible para los valores enteros
      • correctamente ámbito /identificador de choque asuntos tratados muy bien
      • inflexible, pero a un gran suficientemente firmado-o-unsigned int tamaño con el que usted no tiene control (en C++03)
      • no puede tomar la dirección
      • más fuerte uso de restricciones (por ejemplo, el incremento de los – template <typename T> void f(T t) { cout << ++t; } no compila)
      • cada una constante del tipo tomado de la envolvente de la enumeración, por lo que template <typename T> void f(T) obtener una clara creación de instancias cuando pasó por el mismo valor numérico de diferentes enumeraciones, todos los cuales son distintos de los reales de f(int) la creación de instancias.
      • incluso con typeof, no puede esperar que numeric_limits para proporcionar información útil
      • la enumeración typename pueden aparecer en varios lugares en RTTI, mensajes del compilador, etc. – posiblemente útil, posiblemente ofuscación

    Como regla general, yo uso consts y tenerlas en cuenta en la mayoría de los profesionales de la opción para el uso general (a pesar de que los otros tienen la simplicidad atractivo a este viejo perezoso programador).

    OriginalEl autor Tony Delroy

  5. 0

    Macros no respetan alcance, y una macro del nombre puede no estar disponible para un depurador simbólico. Dan Saks tiene un muy completo artículo sobre los méritos relativos de las macros (ninguno), constante de objetos, y las constantes de enumeración. Como Stephen Dewhurst, Saks prefiere las constantes de enumeración para valores enteros, ya que no toman de almacenamiento (más precisamente, las constantes de enumeración no tienen ni el tiempo de almacenamiento ni de la vinculación).

    OriginalEl autor Gnawme

  6. 0

    definir se pueden redefinir , pero const será causa de error del compilador:

    ejemplo:
    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;
    }

    OriginalEl autor Phạm Mạnh

  7. -1

    Una macro siempre tienen un tipo, por ejemplo, #define FIVE 5 es de tipo int.

    Una ventaja para la const variable más de la macro podría ser el uso de la memoria : Con una macro, el valor puede ser duplicado en todas las partes que se utiliza una constante de variables no pueden ser duplicados en la memoria. (pero no estoy seguro de esta diferencia)

    Una macro no no tiene un tipo. En tu ejemplo, 5 tiene un tipo, pero FIVE no tiene ningún tipo, porque se desvanece desde el programa antes de que tipos son introducidas (traducción de la fase 4 en lugar de 7). Esto no es sólo reglas-discente: si escribo #define L_(x) x##L; #define L(x) L_(x); y, a continuación,L(FIVE); el resultado de la expansión será 5L, que tiene el tipo long.

    OriginalEl autor BenjaminB

Dejar respuesta

Please enter your comment!
Please enter your name here