Форум программистов, компьютерный форум, киберфорум
C (Си)
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
из племени тумба-юбма
1713 / 1245 / 243
Регистрация: 29.11.2015
Сообщений: 6,004
Записей в блоге: 12
1

Объявление массива - Компилятор не воспринимает константу

09.12.2020, 23:07. Просмотров 1853. Ответов 17
Метки нет (Все метки)

вот если такой вариант в коде:
C
1
2
    const int N=10;
    char s[N] = "1234567890";
То выдает ошибку: [Error] variable length array 's' is used [-Werror=vla]
Но если сделаю так:
C
1
#define N 10
то все отлично.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.12.2020, 23:07
Ответы с готовыми решениями:

Почему компилятор не воспринимает define константу
Почему ни GCC, ни VS 2010 не компилируют следующий код из книги Шилдта "Самоучитель по С++"?...

Компилятор не воспринимает метод
Здравствуйте. У меня возникла очень странная ошибка, компилятор не воспринимает умножение, выдает...

Компилятор не воспринимает FindWindow
Добрый день дорогие форумчане! Столкнулся с такой проблемой. Раньше была написана программа в...

Компилятор не воспринимает русские буквы
Допустим. дано предложение: "Я хочу выучить С++". Нужна найти количество вхождений буквы "о" в...

17
Эксперт C
25203 / 15683 / 3349
Регистрация: 24.12.2010
Сообщений: 34,162
10.12.2020, 12:50 2
мама Стифлера, N = 11
0
из племени тумба-юбма
1713 / 1245 / 243
Регистрация: 29.11.2015
Сообщений: 6,004
Записей в блоге: 12
10.12.2020, 15:12  [ТС] 3
странно в онлайн компиляторе, такой код:
C
1
2
3
4
5
6
7
8
9
#include <stdio.h>
//#define N 20
 
int main(){
    const int N=20;
    char s[N] = "qwert";
    scanf("%s", s);
    printf("%s", s);
}
тоже выдает ошибку
Код
main.c: In function ‘main’:
main.c:7:5: error: variable-sized object may not be initialized
     char s[N] = "qwert";
     ^~~~
но вот такой код компилируется и работает:
C
1
2
3
4
5
6
7
8
9
#include <stdio.h>
//#define N 20
 
int main(){
    const int N=20;
    char s[N];
    scanf("%s", s);
    printf("%s", s);
}
А в моем компиляторе любой вариант, выдает ошибку как в посте #1.
Наверно это как то связано с установленным у меня префиксом -Werror=vla. Видимо данный префикс разрешает только препроцессорные константы типа define, а все остальное считает переменными.
0
170 / 130 / 51
Регистрация: 18.07.2017
Сообщений: 682
11.12.2020, 11:38 4
Цитата Сообщение от мама Стифлера Посмотреть сообщение
C++
1
char s[N] = "qwert";
"qwert" - const char*. Следовательно данные по этому указателю не изменяются. А раз они не изменяются, то нет и смысла выделять больше памяти чем требуется для указанной строки. На это намекает допустимость таких конструкций:
C++
1
2
char s[] = "ser";
const char* p = "xjfrefxd";
Могу ошибаться, но вроде компиляторы такие строки располагают в секции данных, которая ридонли для исполняемой программы. Так что если хочется засунуть константную строку в массив символов произвольного размера (большего чем строка как правило) и потом менять, то ее можно скопировать например.
C++
1
2
3
int i = 30; // Современные компиляторы могут и без const
char s[i];
strcpy(s, "xdjghgfzskg");
0
Эксперт C
25203 / 15683 / 3349
Регистрация: 24.12.2010
Сообщений: 34,162
11.12.2020, 12:14 5
assemberist, насколько мне известно,
C
1
2
3
4
5
6
char s[6] = "qwert"; // просто выделит в стеке 6 байт и заполнит его. Писать туда можно
char ss[] = "qwert"; // Сделает в точности тоже самое, только компилятор сам вычислит размер
char sss[5] = "qwert"; // вызовет ошибки компиляции, так места не достаточно
char *p = "qwert"; // Поместит строку "qwert" в память ридонли (не обязательно, но может)
                            // p[0] = 'a' вызовет ошибку времени вополнение
                            // Однако, выражение p = "xyz" допустимо.
Не претендую на истину в последней инстанции, но при написании своих серьезных программ я исходил из этих предположений.
Вот такое вполне работает
C
1
2
3
char b[80] = "";  // по умолчанию строка пуста
....
strcpy(b, "qwert");
0
170 / 130 / 51
Регистрация: 18.07.2017
Сообщений: 682
11.12.2020, 13:30 6
Цитата Сообщение от Байт Посмотреть сообщение
Вот такое вполне работает
Да, переменные вычисляются и используются в рантайме, а дефайны подставляются на этапе компиляции. Похоже раз компилятор не может определить во время компиляции размер массива, то не может ручаться за то поместится ли туда какое либо значение. Поэтому такой финт запрещен.
0
425 / 296 / 97
Регистрация: 02.10.2008
Сообщений: 1,139
Записей в блоге: 1
11.12.2020, 15:07 7
Цитата Сообщение от assemberist Посмотреть сообщение
Похоже раз компилятор не может определить во время компиляции размер массива
Но ведь объявлено const int N=10, а значит:
Цитата Сообщение от assemberist Посмотреть сообщение
которая ридонли для исполняемой программы.
0
170 / 130 / 51
Регистрация: 18.07.2017
Сообщений: 682
11.12.2020, 16:27 8
Цитата Сообщение от drfaust Посмотреть сообщение
Но ведь объявлено const int N=10, а значит:
const int N - переменная (неизменяемая). А поскольку:
Цитата Сообщение от assemberist Посмотреть сообщение
переменные вычисляются и используются в рантайме
то, компилятор не может определить во время компиляции размер массива. Но я не знаю как на такую ситуацию смотрит стандарт: это ошибка или разработчики компилятора вправе разрешать такие ситуации на свое усмотрение.
0
96 / 98 / 30
Регистрация: 21.10.2012
Сообщений: 320
12.12.2020, 18:27 9
Самое интересное это то, что компилятор gcc не позволяет задавать константный размер массива при помощи квалификатора const, а компилятор clang разрешает так делать и не выдаёт никаких ошибок.

В общем, этот кусок кода в gcc выдаёт ошибку: variable-sized object may not be initialized
А компилятор clang это спокойно кушает и абсолютно не возмущается.

C
1
2
3
4
5
6
int main()
{
    const int size_str = 6;
    char str[size_str] = "Hello";
    return 0;
}
0
425 / 296 / 97
Регистрация: 02.10.2008
Сообщений: 1,139
Записей в блоге: 1
12.12.2020, 19:00 10
Denno, Уровень оптимизации надеюсь 0? А то мало ли что там в компилерах есть - если в проге нет обращения к памяти по указателю на константную переменную - могут оптимиировать её в дефайн и впилить прямо в код программы.

З.Ы. Да. Тут надо лезть в стандарт, и походу там может нарисоваться UB.

Логически - Си может через разыменование указателей изменить const переменную (если ОС или железо в контроллёрах не проследит за этим)
0
Эксперт C
25203 / 15683 / 3349
Регистрация: 24.12.2010
Сообщений: 34,162
12.12.2020, 19:25 11
С этими массивами дело темное. В первозданном Си массив можно было задавать только так
C
1
2
3
4
5
6
int Arr[10];
            // Конечно, можно было и так
#difine N 10
int Arr[N];
// Но никак иначе.
// Или - динамически через malloc
Потом в одном из стандартов придумали такую фичу
C
1
2
3
int n;
scanf("&d", &n);
int Arr[n];  // Непременно после ввода значения n
Удобно. Новичкам особенно.
Следом за Си решили и в С++ это устандартить.. И в каком-то стандарте так и было. Потом спохватились, что-то там не состыковывалось, и из стандарта выключили. Оставили на усмотрении разработчикам трансляторов. А в чистом Си, кажись, так и осталось...
Так что если хотите спокойной и независимой жизни, лучше эту фичу нигде не применять. Применяете? Будто готовы разбираться с компиляторами вместо того чтобы делом заниматься.
0
425 / 296 / 97
Регистрация: 02.10.2008
Сообщений: 1,139
Записей в блоге: 1
12.12.2020, 19:37 12
Цитата Сообщение от Байт Посмотреть сообщение
Так что если хотите спокойной и независимой жизни, лучше эту фичу нигде не применять. Применяете? Будто готовы разбираться с компиляторами вместо того чтобы делом заниматься.
Согласен. Непоняток лучше избегать.

Кстати, может быть разница в поведении среди локальных и глобальных массивов. Локальный - как раз таки можно выделить в стеке по реальной переменной "в процессе вычисления", а вот глобальный - только на этапе компиляции.
0
из племени тумба-юбма
1713 / 1245 / 243
Регистрация: 29.11.2015
Сообщений: 6,004
Записей в блоге: 12
12.12.2020, 19:42  [ТС] 13
Цитата Сообщение от Байт Посмотреть сообщение
Так что если хотите спокойной и независимой жизни, лучше эту фичу нигде не применять
Да причем тут фича с локальной переменной?
Речь идет о константных переменных
C
1
2
const int N = 10
Arr[10];
и
C
1
2
#define N 10
Arr[10];
В первом случае ошибка, во втором работает. Denno, уже написал, что clang не возмущается, а gcc конючит.
0
425 / 296 / 97
Регистрация: 02.10.2008
Сообщений: 1,139
Записей в блоге: 1
12.12.2020, 20:50 14
Я про это - стандарт позволяет обходными путями изменить конст-переменную (ну и слово...)
Цитата Сообщение от мама Стифлера Посмотреть сообщение
Речь идет о константных переменных
Цитата Сообщение от drfaust Посмотреть сообщение
Си может через разыменование указателей изменить const переменную (если ОС или железо в контроллёрах не проследит за этим)
0
170 / 130 / 51
Регистрация: 18.07.2017
Сообщений: 682
13.12.2020, 00:59 15
Цитата Сообщение от мама Стифлера Посмотреть сообщение
В первом случае ошибка, во втором работает.
Во втором случае во время компиляции все N заменяются на 10. А в первом N - полноценная переменная. Да, const int - такая же переменная как и просто int. И значение она имеет лишь в рантайме. Так что ее нельзя заменить на 10 просто так.
Цитата Сообщение от мама Стифлера Посмотреть сообщение
Denno, уже написал, что clang не возмущается, а gcc конючит.
Потому что ничто не мешает мне сделать вот так:
C++
1
2
3
4
5
6
7
8
int main(){
    int i = 30;
    while(--i){
        const int j = i;
        char s[j];  // может работать, потому что ничего не нужно инициализировать
        //char s[j] = "1";  // вызовет ошибку даже у clang
    }
}
В данном коде j становится числами от 1 до 29 даже без магии с указателями.
0
из племени тумба-юбма
1713 / 1245 / 243
Регистрация: 29.11.2015
Сообщений: 6,004
Записей в блоге: 12
13.12.2020, 01:22  [ТС] 16
Цитата Сообщение от assemberist Посмотреть сообщение
В данном коде j становится числами от 1 до 29 даже без магии с указателями
тогда я снова в ступоре и совсем не понимаю назначение типа const, если оно изменяемое

Добавлено через 2 минуты
хотя, в вашем коде, вы же переменную j, каждый раз объявляете заново, тогда наверно возможно
0
170 / 130 / 51
Регистрация: 18.07.2017
Сообщений: 682
13.12.2020, 01:43 17
Цитата Сообщение от мама Стифлера Посмотреть сообщение
не понимаю назначение типа
Самое известное применение - const char*. В данном случае запрещается менять данные по указателю, но можно читать и копировать и менять положение самого указателя.
Цитата Сообщение от мама Стифлера Посмотреть сообщение
если оно изменяемое
Оно неизменяемое во время жизни const переменной.
1
425 / 296 / 97
Регистрация: 02.10.2008
Сообщений: 1,139
Записей в блоге: 1
13.12.2020, 10:05 18
Прикол про разыменование:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
faust@archlinux ~/П/C/РАзная всячина> cat 11111.c && gcc 11111.c && ./a.out 
#include <stdio.h>
 
const int A=10;
void main()
{
/*    const int A=10;*/
    int *ptr;
    printf("A = %d\n",A);
    ptr = (int *)&A;
    printf("&A = 0x%p\n",ptr);
    
    *ptr = 5;                                                                                                                                                                                                       
    printf("A = %d\n",A);                                                                                                                                                                                           
                                                                                                                                                                                                                    
}A = 10                                                                                                                                                                                                             
&A = 0x0x562ea8a4a004                                                                                                                                                                                               
fish: './a.out' terminated by signal SIGSEGV (Address boundary error)
faust@archlinux ~/П/C/РАзная всячина> cat 22222.c && gcc 22222.c && ./a.out
#include <stdio.h>                                                                                                                                                                                                  
                                                                                                                                                                                                                    
/*const int A=10;*/                                                                                                                                                                                                 
void main()                                                                                                                                                                                                         
{                                                                                                                                                                                                                   
    const int A=10;                                                                                                                                                                                                 
    int *ptr;                                                                                                                                                                                                       
    printf("A = %d\n",A);
    ptr = (int *)&A;
    printf("&A = 0x%p\n",ptr);
    
    *ptr = 5;
    printf("A = %d\n",A);
 
}A = 10
&A = 0x0x7ffc280034dc
A = 5
faust@archlinux ~/П/C/РАзная всячина>
Стек read/write, а вот если в глобал (не помню сегмент bss вроде) - уже readonly на уровне ОС (линукс). В ДОСе и первый пример сработал бы...
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.12.2020, 10:05

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

Объявление графа через входной файл или константу
Доброго времени суток! В приведенном примере кода ввод графа осуществляется пользователем, вместо...

Оптимизирует ли компилятор код при использовании функции, возвращающей константу?
Объясните мне компиляторы С++ оптимизируют такой код?. Да и вообще компиляторы оптимизуруют это? Я...

Компилятор не распознает объявление класса
Суть, есть класс map , основное поле это struct MapTile{ Object_map * Obj; char Fon; ...

Компилятор не видит объявление класса
//Cperson.h #pragma once #include &quot;variables.h&quot; #include &quot;Caudio.h&quot; #include &quot;Cblock.h&quot;...

Компилятор не видит объявление идентификатора
Есть такое вот объявление: __int64 res; res = 0; И уже на res = 0 компилятор не может...

Компилятор не принимает объявление указателя на функцию
Портирую библиотеку коннектора на си для tarantool. Код целиком тут. Туллчейн - cygwin - cmake -...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.