2009-09-13 11 views
7

Me han dicho que si estoy codificando en ANSI-C para declarar en el orden en que se usarán las variables, afirme que los punteros no son nulos y que los índices están dentro de límites, y para inicializar justo antes del uso de la variable.C: Comportamiento de la palabra clave `const`

Si declaro un const ¿puedo inicializarlo después de un bloque de aserciones y código? En Java las inicializaciones finales deben ocurrir en la declaración, pero ¿es consistente a través de las implementaciones ANSI-C que puedo inicializar una const una vez pero no necesariamente en el momento de la declaración?

Respuesta

9

El compilador Java tiene una pequeña cantidad de lógica de flujo para permitirle iniciar las variables final después de su declaración.Esto es legal de Java:

final int something; 

if (today == Friday) 
    something = 7; 
else 
    something = 42; 

Java detectará si las ramas salen del valor final definido. No va a analizar las condiciones, así que esto no es legal en Java, aunque es lógicamente similar:

final int something; 

if (today == Friday) 
    something = 7; 

if (today != Friday) 
    something = 42; 

En ANSI C89, const variables (que no sean extern) debe ser inicializado en el estado en que se declaran en.

const int something = (today == Friday) ? 7 : 42; 

el extern modificador en una declaración indica al compilador que la variable se inicializa en una unidad de Complation diferente (o en otro lugar en esta unidad de compilación).

En ANSI C99, puede mezclar declaraciones y códigos, por lo que puede declarar e inicializar una variable const después de un bloque de aserciones y códigos. La portabilidad de 1999 ANSI C sigue siendo un problema.

Un trabajo en torno a C89 es tener en cuenta que las normas para las declaraciones anteriores de trabajo de código en el ámbito de bloque en lugar de ámbito de la función, por lo que se puede hacer esto:

#include<stdio.h> 

int main (void) 
{ 
    printf ("wibble\n"); 

    { 
     const int x = 10; 

     printf ("x = %d\n", x); 
    } 

    return 0; 
} 
+1

@Pete: 2x Lecciones aprendidas. –

+1

En realidad, puede declarar variables const * global * no externas sin inicializarlas. 'const int a;' se llama una "definición tentativa", o algo así.Si la variable se define posteriormente sin ambigüedades, se trata como una simple declaración. Si no, es una definición. Entonces puede tener 'const int a;' en un encabezado, y luego 'const int a = 12;' en el archivo .c. No es que a menudo quieras, ya que te arriesgas a olvidar la definición y terminar con 'a' siendo 12 en algunas unidades de compilación y 0 en otras ... –

+0

@onebyone: De hecho, las "definiciones tentativas" no conducen a diferentes valores en diferentes unidades de compilación. Intente compilar "int x;" en un archivo y "int x = 1;" en otro. La variable x contiene 1 en ambos archivos después del enlace (con todos los compiladores que probé). Este es el comportamiento ampliamente implementado, aunque no leo C99 como especificando exactamente esto. –

3

const Las variables son de solo lectura y se deben inicializar en el lugar en que están definidas.

Este código produce error: assignment of read-only variable 'foo' (gcc4):

const int foo; 
foo = 4; 

Lo mismo va para los punteros const (nota aquí: const int * no es un puntero constante, sino un puntero a const):

int * const foo; 
foo = 4; 
+0

¿El último ejemplo necesita * foo = 4; para generar el error? Debido a que la asignación de 4 sería simplemente usando un valor de puntero improbable ... –

+0

Depende de qué error se trate. 'foo = 4' es un error de compilación porque foo es const. '* foo = 4' es un error en tiempo de ejecución (y con suerte una advertencia en tiempo de compilación) porque foo no está inicializado (o se inicializa a NULL si es global). –

1

Si usted está hablando de dividir una definición

const int x = 2; 

en dos partes:

const int x; 

x=2; 

me temo que eso no es posible en C.

Si yo fuera usted, me gustaría tratar de asegurarse de que entiendo la intención de las reglas de codificación que usted describe. Dudo que algunas reglas de codificación impidan inicializar variables (incluso variables no const).

En respuesta a varios comentarios:

const int * p; 

no es una declaración de una variable const. Es una declaración de una variable de puntero no const a un const int.

Se puede declarar

extern const int x; 

pero todavía no se puede inicializar x después de haber ejecutado el código, controles de aseveración, ...

+0

+1. Probablemente, la intención de "inicializar justo antes de usar" es (1) de modo que el valor inicial esté físicamente cerca del código que se basa en él, y/o (2) si funciona la inicialización que a veces se puede evitar, colocándolo cerca el primer uso es la mejor regla de oro para maximizar la probabilidad de evitarlo. Entonces tienes que sopesar esas dos cosas contra el valor de marcarlo const. –

+0

Sí, me llevó la respuesta de Pavel Shved darme cuenta de que la pregunta era probablemente sobre las variables de const locales. Estaba pensando en variables globales todo este tiempo. –

2

No se puede inicializar la const después de la declaración dentro del cuerpo de la función, pero se puede simplemente abrir una cuadra después de sus afirmaciones:

void func() 
{ 
    int y; 
    //do assertions 
    assert(something); 
    { 
     int const x = 5; 
     // function body 
    } 
} 
3

Tenga en cuenta que incluso en C89, a menudo se puede mover la definición más cerca del punto de inicio del consumo por introduci ng un bloque desnudo solo para el alcance extra. Antes:

int a, b, c; 

a = 12; 
// do some stuff with a 

b = 17; 
// do some stuff with a and b 

c = 23; 
// do some stuff with a, b, and c 

Después:

int a = 12; 
// do some stuff with a 
{ 
    int b = 17 
    // do some stuff with a and b 
    { 
     int c = 23; 
     // do some stuff with a, b and c 
    } 
} 

Con C99, por supuesto, se pueden definir variables distintas al comienzo de un bloque:

int a = 12; 
// do some stuff with a 

int b = 17 
// do some stuff with a and b 

int c = 23; 
// do some stuff with a, b and c 
2

cortos del ámbito de bloque y C99 métodos de declaración otros han demostrado, la respuesta es no; no puede aplazar la inicialización de una variable const. De todos modos, const no es muy útil para las variables locales. Los principales veces utilizo la palabra clave const en C son:

  • punteros en argumentos de la función (o punteros variables locales a base de argumentos) donde la función es en honor a un contrato a no modificar los datos de puntas a. La palabra clave const ayuda a garantizar que la implementación de la función respete el requisito de no modificar (requiere un esfuerzo especial para deshacerse de const) y permite que este requisito se propague a través de múltiples llamadas a funciones.
  • Para declarar tablas constantes en tiempo de compilación (tablas de búsqueda, objetos permanentes predefinidos, etc.) que quiero almacenar en una sección de solo lectura del binario para que no usen recursos físicos adicionales en tiempo de ejecución.

A veces declaro que las variables locales son const si creo que ayudarán al lector a entender una función, pero eso es bastante raro.

0

Si desea deshacerse de la const en el LHS, ¿qué tal esto?

const int n = 0; 

*((int*)&n) = 23; 
+1

¿Qué tal esto? Muy mala idea Evita las restricciones que el lenguaje ha decidido implementar. Incluso puede causar errores, dependiendo de la implementación del compilador. – einpoklum

Cuestiones relacionadas