Al revisar el código, aplico las siguientes reglas:
-
Siempre use const
para los parámetros de función pasados por referencia donde
La función no modifica (ni libera) los datos a los que apunta.
int find(const int *data, size_t size, int value);
-
Siempre use const
para las constantes que de otra manera podrían definirse usando #define o enum. El compilador puede ubicar los datos en la memoria de solo lectura (ROM) como resultado (aunque el vinculador es a menudo una mejor herramienta para este propósito en sistemas integrados).
const double PI = 3.14;
-
Nunca use const en una función prototipo para un parámetro pasado
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 sea apropiado, use const volatile
en ubicaciones que el programa no puede cambiar pero que aún pueden 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 función implementació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 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. Por supuesto, el compilador puede determinar que una variable no se modifica, pero al agregar const
, se permite que se cumpla. Esto puede ayudar al lector y agregar algo de seguridad (aunque si sus funciones son grandes o
Lo suficientemente complicado como para que esto haga una gran diferencia, posiblemente tenga otros
problemas). Editar - por ejemplo. Una función codificada densamente de 200 líneas con bucles anidados y muchos largos
o nombres de variables similares, sabiendo que ciertas variables nunca cambian podrían
Facilidad de entender significativamente. Tales funciones han sido mal diseñadas o
Mantenido.
Problemas con const
. Probablemente escuchará el término "envenenamiento constante".
Esto ocurre cuando la adición de const
a un parámetro de función hace que 'constness'
propagar.
Editar - envenenamiento por const: 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 tome
un codigo%. Y así sucesivamente si const
pasa el function_b
a str
,
Como puede imaginar, esto podría ser doloroso si se propaga en muchos
archivos / módulos separados. Si se propaga en una función que no puede ser
cambiado (por ejemplo, una biblioteca del sistema), entonces se hace necesario un lanzamiento. Así que espolvorear
Tal vez el function_c
en el código existente está pidiendo problemas. En código nuevo
sin embargo, es mejor que const
califique consistentemente cuando sea apropiado.
El problema más insidioso de const
es que no estaba en el original
idioma. 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, compilar y
ejecute este código y (dependiendo del compilador / opciones) puede bloquearse cuando
ejecutar:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = 'int find(const int *data, size_t size, int value);
';
const
devuelve un strchr
no un char*
. Como su parámetro de llamada es
const char*
debe convertir el parámetro de llamada a const
. Y en este caso que
desecha la propiedad de almacenamiento de sólo lectura real. Editar: - esto se aplica generalmente a las variables 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 en 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 ten cuidado: cuando
tiene constantes de real (es decir, almacenadas en la ROM), debe tener mucho cuidado de no
perder su constness.