Подтвердить что ты не робот

Почему int x [n] неверно, где n - значение const?

Я не понимаю, почему это неправильно:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

хотя n уже является значением const.

Хотя это кажется правильным для компилятора GNU:

const int n = 5;
int x[n]; /*without initialization*/

Я знаю о функции VLA на C99, и я думаю, что это связано с тем, что происходит, но Мне просто нужно уточнить, что происходит в фоновом режиме.

4b9b3361

Ответ 1

Главное помнить, что const и "constant" означают две совершенно разные вещи.

Ключевое слово const означает "только для чтения". Константа - это числовой литерал, такой как 42 или 1.5 (или константа перечисления или символа). Постоянное выражение - это особый вид выражения, который может быть оценен во время компиляции, например 2 + 2.

Так что дано объявление:

const int n = 5;

выражение n относится к значению объекта и не рассматривается как константное выражение. Типичный компилятор будет оптимизировать ссылку на n, заменив ее на тот же код, который будет использоваться для литерала 5, но это не требуется - и правила для константы выражения определяются языком, а не по умности текущего компилятора.

Пример разницы между const (только для чтения) и константой (оцененной во время компиляции):

const size_t now = time(NULL);

Ключевое слово const означает, что вам не разрешено изменять значение now после его инициализации, но значение time(NULL) явно не может быть вычислено до времени выполнения.

Итак, это:

const int n = 5;
int x[n];

больше не действует в C, чем без ключевого слова const.

Язык может (и IMHO, вероятно, должен) оценивать n как постоянное выражение; это просто не определено именно так. (У С++ есть такое правило, см. Стандарт С++ или достойную ссылку для деталей gory.)

Если вам нужна именованная константа со значением 5, наиболее распространенным способом является определение макроса:

#define N 5
int x[N];

Другой подход заключается в определении константы перечисления:

enum { n = 5 };
int x[n];

Константы континуума являются постоянными выражениями и всегда имеют тип int (что означает, что этот метод не будет работать для типов, отличных от int). И это, возможно, злоупотребление механизмом enum.

Начиная с стандарта 1999 года, массив может быть определен с непостоянным размером; это VLA или массив переменной длины. Такие массивы разрешены только в области блока и могут не иметь инициализаторов (поскольку компилятор не может проверить, что инициализатор имеет правильное количество элементов).

Но с учетом вашего исходного кода:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

вы можете позволить компилятору вывести длину из инициализатора:

int x[] = { 1,1,3,4,5 };

И вы можете вычислить длину из размера массива:

const int x_len = sizeof x / sizeof x[0];

Ответ 2

Почему int x[n] неверно, если n является значением const?

n не является константой. const только обещают, что n является переменной только для чтения, которая не должна быть изменена во время выполнения программы.
Обратите внимание, что в c, в отличие от , const квалифицированные переменные не являются постоянными. Следовательно, объявленный массив представляет собой массив переменной длины.
Вы не можете использовать список инициализаторов для инициализации массивов переменной длины.

С11-§6.7.9/3:

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

Вы можете использовать #define или enum, чтобы сделать n константу

#define n 5
int x[n] = { 1,1,3,4,5 };   

Ответ 3

Если вы исчерпывающе инициализируете массив, то это проще, безопаснее и удобнее обслуживать, чтобы компилятор выводил размер массива:

int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ; 

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

Ответ 4

Даже если n является const, вы не можете использовать его для определения размера массива, если вы не хотите создавать VLA. Однако вы не можете использовать список инициализаторов для инициализации VLA.

Используйте макрос для создания массива фиксированного размера.

#define ARRAY_SIZE 5

int x[ARRAY_SIZE] = { 1,1,3,4,5 };

Ответ 5

Является ли ваш код семантически отличным от myfunc() здесь:

void myfunc(const int n) { 
    int x[n] = { 1,1,3,4,5 };
    printf("%d\n", x[n-1]);
    *( (int *) &n) = 17;    //  Somewhat less "constant" than hoped...
    return ;
}

int main(){
    myfunc(4);
    myfunc(5);
    myfunc(6);  //  Haven't actually tested this.  Boom?  Maybe just printf(noise)?
    return 0;
}

Является ли n действительно всей этой константой? Сколько пространства вы считаете компилятором для x[] (поскольку это задание для компилятора)?

Как указывали другие, cv-qualifier const не означает "значение, которое является постоянным во время компиляции и для всех времен после". Это означает "значение, которое локальный код не должен изменять (хотя он может)".