Al revisar el código, aplico las siguientes reglas:
Utilice siempre const
para parámetros de función pasados por referencia donde la función no modifica (o libera) los datos apuntados.
int find(const int *data, size_t size, int value);
Utilice siempre const
para constantes que de otro modo podrían definirse utilizando un #define o una enumeración. Como resultado, el compilador puede ubicar los datos en la memoria de solo lectura (ROM) (aunque el enlazador suele ser una mejor herramienta para este propósito en los sistemas integrados).
const double PI = 3.14;
Nunca use const en un prototipo de función para un parámetro pasado por
valor . No tiene significado y, por lo tanto, es solo 'ruido'.
// don't add const to 'value' or 'size'
int find(const int *data, size_t size, const int value);
Cuando corresponda, úselo const volatile
en ubicaciones que el programa no pueda cambiar, pero que podrían cambiar. Los registros de hardware son el caso de uso típico aquí, por ejemplo, un registro de estado que refleja el estado de un dispositivo:
const volatile int32_t *DEVICE_STATUS = (int32_t*) 0x100;
Otros usos son opcionales. Por ejemplo, los parámetros de una función dentro de la implementación de la función se pueden marcar como const.
// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)
{
... etc
o la función devuelve valores o cálculos que se obtienen y luego nunca cambian:
char *repeat_str(const char *str, size_t n)
{
const size_t len = strlen(str);
const size_t buf_size = 1 + (len * n);
char *buf = malloc(buf_size);
...
Estos usos de const
solo indican que no cambiará la variable; no cambian cómo o dónde se almacena la variable. El compilador, por supuesto, puede determinar que una variable no se cambia, pero al agregarla const
le permite hacer cumplir eso. Esto puede ayudar al lector y agregar algo de seguridad (aunque si sus funciones son lo suficientemente grandes o complicadas como para que esto haga una gran diferencia, posiblemente tenga otros problemas). Editar, por ejemplo. una función densamente codificada de 200 líneas con bucles anidados y muchos nombres de variables largos o similares, sabiendo que ciertas variables nunca cambian podría facilitar la comprensión significativamente. Tales funciones han sido mal diseñadas o mantenidas.
Problemas con const
. Probablemente escuchará el término "envenenamiento constante". Esto ocurre cuando agregar const
a un parámetro de función hace que se propague 'constness'.
Editar - envenenamiento constante: por ejemplo en la función:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
si cambiamos str
a const
, entonces debemos asegurarnos de que fuction_b
también se necesita a const
. Y así sucesivamente si se function_b
pasa str
a function_c
, etc. Como puede imaginar, esto podría ser doloroso si se propaga en muchos archivos / módulos separados. Si se propaga a una función que no se puede cambiar (por ejemplo, una biblioteca del sistema), entonces se hace necesaria una conversión. Por lo tanto, rociar el
const
código existente tal vez sea un problema. Sin embargo, en el nuevo código, es mejor const
calificar consistentemente donde sea apropiado.
El problema más insidioso const
es que no estaba en el idioma original. Como complemento, no encaja del todo. Para empezar, tiene dos significados (como en las reglas anteriores, que significa "No voy a cambiar esto" y "esto no se puede modificar"). Pero más que eso, puede ser peligroso. Por ejemplo, compile y ejecute este código y (según el compilador / opciones) puede bloquearse cuando se ejecuta:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';
strchr
devuelve un char*
no a const char*
. Como su parámetro de llamada es
const
, debe enviar el parámetro de llamada a char*
. Y en este caso, eso desecha la verdadera propiedad de almacenamiento de solo lectura. Editar: esto se aplica generalmente a los vars en la memoria de solo lectura. Por 'ROM', me refiero no solo a la ROM física sino a cualquier memoria que esté protegida contra escritura, como sucede con la sección de código de los programas que se ejecutan en un sistema operativo típico.
Muchas funciones de biblioteca estándar se comportan de la misma manera, así que tenga cuidado: cuando tiene constantes reales (es decir, almacenadas en ROM) debe tener mucho cuidado de no perder su const.
Specific issues with software development
. Estoy siendo bastante específico.