C: поведение ключевого слова const

Мне сказали, что если я кодирую в ANSI-C, чтобы объявить в порядке, что переменные будут использоваться, утверждать, что указатели не являются нулевыми и что индексы находятся в пределах границ, и инициализировать непосредственно перед использованием переменной.

Если я объявляю const, могу ли я инициализировать его после блока утверждений и кода? В Java окончательная инициализация должна происходить при объявлении, но является ли она последовательной в реализациях ANSI-C, чтобы я мог инициализировать const один раз, но не обязательно во время объявления?

7 ответов

Решение

Компилятор Java имеет небольшое количество логики потока, чтобы позволить вам инициализировать final переменные после их объявления. Это легальная Java:

final int something;

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

Java обнаружит, если какие-либо ветви оставляют окончательное значение неопределенным. Он не будет анализировать условия, поэтому это недопустимая Java, даже если она логически похожа:

final int something;

if ( today == Friday )
    something = 7;

if ( today != Friday )
    something = 42;

В ANSI C89, const переменные (кроме extern) должны быть инициализированы в заявлении, в котором они объявлены.

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

extern Модификатор в объявлении сообщает компилятору, что переменная инициализируется в другом модуле компиляции (или в другом месте этого модуля компиляции).

В ANSI C99 вы можете смешивать объявления и код, чтобы вы могли объявить и инициализировать const переменная после блока утверждений и кода. Переносимость ANSI C 1999 года остается проблемой.

Обходной путь для C89 состоит в том, чтобы заметить, что правила для объявлений, предшествующих коду, работают в области блока, а не в области функции, поэтому вы можете сделать это:

#include<stdio.h>

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

    {
        const int x = 10;

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

    return 0;
}

const переменные доступны только для чтения и должны инициализироваться там, где они определены.

Этот код производит error: assignment of read-only variable 'foo' (Gcc4):

const int foo;
foo = 4;

То же самое касается константных указателей (обратите внимание: const int * это не указатель const, а указатель на const):

int * const foo;
foo = 4;

Имейте в виду, что даже в C89 вы можете часто перемещать определение ближе к точке первого использования, вводя пустой блок только для дополнительного объема. До:

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

После:

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
    }
}

Конечно, с помощью C99 вы можете определять переменные, отличные от начала блока:

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

Вы не можете инициализировать const после объявления в теле функции, но вы можете просто открыть один блок после ваших утверждений:

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

Если не считать объема блока и методов объявления C99, показанных другими, ответ - нет; Вы не можете отложить инициализацию переменной const. В любом случае, const не очень полезен для локальных переменных. Основное время, когда я использую ключевое слово const в C:

  • Указатели в аргументах функции (или указатели на локальные переменные, основанные на аргументах), где функция выполняет контракт, чтобы не изменять указанные данные. Ключевое слово const помогает гарантировать, что реализация функции соблюдает требование не изменять (оно требует особых усилий приведения, чтобы избавиться от const) и позволяет этому требованию распространяться через несколько вызовов функций.
  • Для объявления постоянных таблиц времени компиляции (справочных таблиц, предопределенных постоянных объектов и т. Д.), Которые я хочу сохранить в секции только для чтения двоичного файла, чтобы они не использовали дополнительные физические ресурсы во время выполнения.

Иногда я объявляю локальные переменные const, если думаю, что это поможет читателю понять функцию, но это довольно редко.

Если вы говорите о разделении определения

const int x = 2;

на две части:

const int x;

x=2;

Боюсь, что это невозможно в C.

На вашем месте я бы постарался понять смысл правил кодирования, которые вы описали. Я сомневаюсь, что нормальные правила кодирования предотвратят инициализацию переменных (даже неконстантных).

В ответ на различные комментарии:

const int * p;

НЕ является объявлением константной переменной. Это объявление неконстантной переменной-указателя на const int.

Вы можете объявить

extern const int x;

но вы все еще не можете инициализировать x после выполнения кода, проверки утверждений,...

Если вы хотите отказаться от const на LHS, как насчет этого?

const int n = 0;

*((int*)&n) = 23;
Другие вопросы по тегам