En cuanto a muchas preguntas, la respuesta de esta pregunta es que depende . En lugar de decir cuál es mejor, he dado ejemplos y objetivos donde uno es mejor que otro.
Tanto el preprocesador como la constante tienen sus propios lugares de uso apropiado.
En el caso del preprocesador, el código se elimina antes del tiempo de compilación. Por lo tanto, es más adecuado para situaciones en las que se espera que el código no se compile . Esto puede afectar la estructura del módulo, las dependencias y puede permitir seleccionar los mejores segmentos de código para los aspectos de rendimiento. En los siguientes casos, uno debe dividir el código usando solo un preprocesador.
Código multiplataforma:
por ejemplo, cuando el código se compila en diferentes plataformas, cuando el código depende de números de versión específicos del sistema operativo (o incluso de la versión del compilador, aunque esto es muy raro). Por ejemplo, cuando se trata de contrapartes de código little-endien big-endien, deben segregarse con preprocesadores en lugar de constantes. O si está compilando código para Windows también Linux y ciertas llamadas al sistema son muy diferentes.
Parches experimentales:
Otro caso en el que esto es tener un justificado es algún código experimental que es arriesgado o ciertos módulos principales que deben omitirse, lo que tendrá un vínculo significativo o una diferencia de rendimiento. La razón por la que uno desearía deshabilitar el código a través del preprocesador en lugar de esconderse debajo de if () es porque es posible que no estemos seguros de los errores introducidos por este conjunto de cambios específico y que estemos ejecutándonos de manera experimental. Si falla, no debemos hacer nada más que deshabilitar ese código en producción que reescribir. En algún momento es ideal #if 0
para comentar todo el código.
Manejo de dependencias:
otra razón por la que es posible que desee generar Por ejemplo, si no desea admitir imágenes JPEG, puede ayudar a deshacerse de compilar ese módulo / código auxiliar y, finalmente, la biblioteca no se vinculará (estática o dinámicamente) a ese módulo. A veces, los paquetes se ejecutan ./configure
para identificar la disponibilidad de dicha dependencia y, si las bibliotecas no están presentes (o el usuario no quiere habilitar), dicha funcionalidad se deshabilita automáticamente sin vincularse con esa biblioteca. Aquí siempre es beneficioso si estas directivas se generan automáticamente.
Licencias:
Un ejemplo muy interesante de directiva de preprocesador es ffmpeg . Tiene códecs que potencialmente pueden infringir patentes por su uso. Si descarga la fuente y compila para instalar, le pregunta si desea o no mantiene esas cosas. ¡Mantener los códigos ocultos bajo algunos si las condiciones aún pueden llevarte a la corte!
Código copiar y pegar:
macros Aka. Este no es un consejo para el uso excesivo de macros, solo que las macros tienen una forma mucho más poderosa de aplicar el equivalente de copiar pasado . Pero úsalo con mucho cuidado; y úsalo si sabes lo que estás haciendo. Constantes, por supuesto, no pueden hacer esto. Pero también se pueden usar inline
funciones si eso es fácil de hacer.
Entonces, ¿cuándo usas constantes?
Casi en todas partes.
Flujo de código más ordenado:
en general, cuando usa constantes, es casi indistinguible de las variables regulares y, por lo tanto, es un código mejor legible. Si escribe una rutina de 75 líneas, tenga 3 o 4 líneas cada 10 líneas con #ifdef es MUY incapaz de leer . Probablemente dada una constante primaria gobernada por #ifdef, y úsela en un flujo natural en todas partes.
Código bien sangrado: todas las directivas de preprocesador, nunca funcionan bien con un código bien sangrado . Incluso si su compilador permite la sangría de #def, el preprocesador Pre-ANSI C no permitió espacio entre el inicio de una línea y el carácter "#"; el "#" inicial siempre debe colocarse en la primera columna.
Configuración:
Otra razón por la cual las constantes o variables tienen sentido es que pueden evolucionar fácilmente de estar vinculadas a globales o en el futuro pueden extenderse para derivarse de los archivos de configuración.
Una última cosa:
nunca USE directivas de preprocesador #ifdef
para #endif
cruzar el alcance o { ... }
. es decir, inicio #ifdef
o fin de #endif
en diferentes lados de { ... }
. Esto es extremadamente malo; puede ser confuso, a veces puede ser peligroso.
Esto, por supuesto, no es una lista exhaustiva, pero muestra una gran diferencia, donde qué método es más apto para usar. Realmente no se trata de cuál es mejor , sino de cuál es más natural usar en un contexto dado.