Форум программистов, компьютерный форум CyberForum.ru

С++ VLA и прочее... - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.89
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.11.2012, 00:17     С++ VLA и прочее... #1
 Комментарий модератора 
Перенесено из Порекомендуйте компилятор


Dev-C++ меня удивляет. Вот такой код компилирует без ошибок и предупреждений:
C++
1
2
3
4
5
6
7
int main()
{
    int m;
    int arr[m];
    
    return 0;
}
А такой и выполняет:
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
 
int main()
{
    int m;
    cin >> m;
    int arr[m];
    
    return 0;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 00:08     С++ VLA и прочее... #21
Добавлено через 19 секунд
Цитата Сообщение от Герц Посмотреть сообщение
Большой знаток C++ пришел :-D
using namespace std; и ни одного C++ заголовка.
ну и чё? забыл убрать, пойти застрелиться с позора...

Добавлено через 1 минуту
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
А ничего, что в стеке хранятся не только записи активаций функций, а и вагон с тележкой другой лабуды вроде записей активаций системных вызовов и SEH-фреймов, и кто-то должен за ними убирать, чтобы user-функции не напоролись на то, что им видеть не положено?
пусть там хранится всё что угодно. Надо знания подгонять под факты, а не наоборот. Если ваши знания противоречат тому, что вы видите, можно тыщу раз пересматривать, в надежде увидеть что-то другое. А я бы усомнился в своих знаниях.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 00:29     С++ VLA и прочее... #22
Компилил
C
1
2
3
4
5
6
7
#include <stdio.h>
 
int main()
{
    char arr [] = "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr";
    return 0;
}
Получил
Assembler
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
    .file   "c.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .section .rdata,"dr"
    .align 4
LC0:
    .ascii "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\0"
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    pushl   %edi
    pushl   %esi
    pushl   %ebx
    subl    $52, %esp
    call    ___main
    leal    15(%esp), %edx
    movl    $LC0, %ebx
    movl    $33, %eax
    movl    %edx, %edi
    movl    %ebx, %esi
    movl    %eax, %ecx
    rep movsb
    movl    $0, %eax
    addl    $52, %esp
    popl    %ebx
    popl    %esi
    popl    %edi
    leave
    ret
И в отладчике main() выглядит так же (см. аттач). Что я делаю не так? Может, смотрю в main() начиная с её настоящей точки входа, а не чёрти знает куда в системный boilerplate-код?
Миниатюры
С++ VLA и прочее...  
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 00:39     С++ VLA и прочее... #23
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
И в отладчике main() выглядит так же (см. аттач). Что я делаю не так? Может, смотрю в main() начиная с её настоящей точки входа, а не чёрти знает куда в системный boilerplate-код?
Ну и чё дальше? Я увидел, что в регистр EBX кладётся адрес строки, скорее всего она лежит в секции данных. Ну и чё? Возьми с полки пирожок. Я так-то до хрена чё в отладчике вижу, я же не волоку сюда всё, что ни попадя.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 00:49     С++ VLA и прочее... #24
А SUB ESP, 0x34 после формирования EBP-фрейма и сохранения регистров такой незаметная, что капец.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 00:55     С++ VLA и прочее... #25
А понял тебя, базара нет, был неправ, бряк ставил не туда, если ты про это.

Но вообще-то если бы я не был уверен в своей правоте я бы не говорил. Итак, перед нами по твоему скриншоту РЕАЛЬНАЯ функций main; так вот, сейчас у тебя в стеке нет строки rrrr.... А стек увеличится и инструкцией 4013D5 в него и положится строка.

Если ты хочешь сказать, что стек увеличится имено инструкцией SUB ESP, 34- кто же спорит? Эта инструкция выполнилась в main, что и требовалось доказать. Стек увеличивается в main. Да, так. Я с самого начал а это говорил. Ну и? Жду дальнейших разоблачений.
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4920 / 2663 / 243
Регистрация: 29.11.2010
Сообщений: 7,405
01.12.2012, 00:58     С++ VLA и прочее... #26
Цитата Сообщение от alsav22 Посмотреть сообщение
MrGluck, не могли бы вы хоть как-то прокоментировать эту цитату. Для меня, как начинающего, сложно понять о чём тут речь.
Без проблем,
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extern int n;
int A[n]; // invalid file scope VLA - неправильная инициализация VLA массива переменной с другого файла. Компилятор может не знать, чему равен n на момент обращения
extern int (*p2)[n]; // invalid file scope VM 
int B[100]; // invalid file scope but not VM 
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope - вполне корректная запись прототипа функции с VLA массивом в качестве параметра
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA - корректная запись, сводится к указателю на VLA массив
{
typedef int VLA[m][m]; // valid: block scope typedef VLA
struct tag {
int (*y)[n]; // invalid: y not ordinary identifier
int z[n]; // invalid: z not ordinary identifier
};
int D[m]; // valid: auto VLA - типичное объявление VLA массива. Некорректно в C90, но соответствует стандарту C99
static int E[m]; // invalid: static block scope VLA
extern int F[m]; // invalid: F has linkage and is VLA
int (*s)[m]; // valid: auto pointer to VLA - объявление указателя на VLA массив также вполне корректно в С99
extern int (*r)[m]; // invalid: r has linkage and points to VLA
static int (*q)[m] = &B; // valid: q is a static block pointer to VLA
}
Таким образом, VLA имеют место быть в компиляторах с поддержкой С99 стандарта. Студия к ним не относится, им вообще на чистый С как-то побоку, их политика - продвижение С#.

Тем не менее, нету подтверждения того, что VLA массивы соответствуют стандарту С++. (Возможно я не нашел, но в С++03 такого точно не было). Но gcc умеет корректно обрабатывать данные запросы, приводя к константе размер массива на момент создания. А учитывая, что никаких плохих последствий из этого не выходит, можно предположить, что данное поведение будет узаконено в будущих стандартах С++ (все же в стандарт С подобную фичу включили). Но не будем загадывать. Код не соответствует стандарту, так делать не желательно, но в gcc (mingw соотв. тоже), данный код не приведет к ошибкам, его использование некорректно, но не критично. Есть и плюсы с такой "фичей" - новички, которые используют динамические массивы (все по фень-шую), очень, ну просто очень часто забывают освободить память, что приводит к утечке, а такого рода ошибки не отлавливаются на стадии компиляции, соотв. особо коварные. Использование VLA помогает решать множество стандартных задач не узнавая про дин. массивы. А со временем, когда дойдет время к изучению операций с памятью, маленькие кодеры прозреют, и запись VLA массивов заменится на связку new-delete.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 01:04     С++ VLA и прочее... #27
Память выделяется в прелюдии подпрограммы. Инициализация проводится после выделения. Обе части расположены между точкой входа и ret, так что в принципе "в теле функции". Полезный код main() (инициализация того массива) начинается уже после прелюдии, в этом смысле память выделяется до выполнения полезного кода main(), но, естественно, после входа в call main. /discuss
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 01:10     С++ VLA и прочее... #28
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Память выделяется в прелюдии подпрограммы
Я тоже могу сказать слово какое-нибудь, например "эпиграф функции" или "закат функции" и ждать, может собеседник подза..ся значение слов выяснять

Выделение памяти под массив и его инициализация происходят между точкой входа и ret, значит в main остальное- суета сует и томление духа. И давай уже завязывать.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 01:26  [ТС]     С++ VLA и прочее... #29
Всё. Окончательно запутался. Если выделение памяти под статический массив происходит во время работы программы, то зачем компилятору знать его размер?
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4920 / 2663 / 243
Регистрация: 29.11.2010
Сообщений: 7,405
01.12.2012, 01:31     С++ VLA и прочее... #30
Цитата Сообщение от alsav22 Посмотреть сообщение
Всё. Окончательно запутался. Если выделение памяти под статический массив происходит во время работы программы, то зачем компилятору знать его размер?
Надо ж знать, сколько выделить.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 01:37     С++ VLA и прочее... #31
Цитата Сообщение от alsav22 Посмотреть сообщение
то зачем компилятору знать его размер?
компилятору необязательно знать его размер; выделяется память как мы выяснили на стадии выполнения и увеличиваемый размер тоже узнаётся на стадии выполнения. И компилятор в этот момент спит спокойным сном, а программа работает.

А вообще противоречий здравому смыслу много. Сделали и сделали, забей. Может, исправятся когда...
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 02:10  [ТС]     С++ VLA и прочее... #32
Цитата Сообщение от kravam Посмотреть сообщение
Выделение памяти под массив и его инициализация происходят между точкой входа и ret, значит в main
Сейчас почитал цитаты, где говорится о выделении памяти. Нигде не говорится, что память выделяется до входа в main(). Везде, или до начала работы main(), или до выполнения кода main(). А как это трактовать неизвестно. Одни так трактуют, другие иначе. Наверное, всё упирается в точное определение: что считать началом выполнения кода функци, вход в main() или что-то другое. Если бы это определение было, то и спорить было бы не о чем.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 03:34     С++ VLA и прочее... #33
Цитата Сообщение от alsav22 Посмотреть сообщение
Наверное, всё упирается в точное определение: что считать началом выполнения кода функци, вход в main() или что-то другое. Если бы это определение было, то и спорить было бы не о чем.
начало функции main это точка входа в main, это одно и то же, узнаётся так:

C++
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
    printf ("%x\n", main);
    getchar ();
    return 0;
}
А вообще смотри, ты говоришь о статических массивах а в пример приводишь локальные и мы все за тобой как попугаи повторяем, с самого начала темы и той и другой. Несём какую-то херь, а того не замечаем что
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
 
int main()
{
    int m;
    cin >> m;
    int arr[m];
    
    return 0;
}
Так-то разобраться, это не статический массив, а локальный. Ибо определён в функции. Ну и что, что она называется main, она ничем от других функций не отличается кроме того, что начинает выполняться первой. Всё предсказуемо, обыкновенное выделение памяти локального массива.

++++++++++++++++++++++++++++++++++++++++++++++++++++++

А статический-то массив вот он:
C++
1
2
3
4
5
6
7
#include <stdio.h>
int m;
int arr[m];
int main()
{
    return 0;
}
И m тут по-любому должна быть известна до выполнения main; на такой код как раз компилятор и ругнётся.
Такие дела.
Цитата Сообщение от alsav22 Посмотреть сообщение
Всё. Окончательно запутался.
теперь-то распутался?

Добавлено через 29 минут
Или. что то же самое:
C++
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
int m;
static int arr[m];
return 0;
}
или
C++
1
2
3
4
5
6
7
8
9
10
void foo () {
int m;
static int arr[m];
return 0;
}
 
int main()
{
 return 0;
}
На всё это компилятор ругается.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 04:29  [ТС]     С++ VLA и прочее... #34
Цитата Сообщение от kravam Посмотреть сообщение
А вообще смотри, ты говоришь о статических массивах а в пример приводишь локальные и мы все за тобой как попугаи повторяем, с самого начала темы и той и другой
Я согласен с этим твоим постом: Размер статического массива Спорить не берусь, но по моему, такое название допустимо. Это всё равно, что статическое и динамическое связывание. К классу памяти это не имеет отношения.
Миниатюры
С++ VLA и прочее...  
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 05:04  [ТС]     С++ VLA и прочее... #35
Цитата Сообщение от kravam Посмотреть сообщение
начало функции main это точка входа в main, это одно и то же
Я же пишу, что
Сейчас почитал цитаты, где говорится о выделении памяти. Нигде не говорится, что память выделяется до входа в main(). Везде, или до начала работы main(), или до выполнения кода main(). А как это трактовать неизвестно. Одни так трактуют, другие иначе. Наверное, всё упирается в точное определение: что считать началом выполнения кода функци, вход в main() или что-то другое. Если бы это определение было, то и спорить было бы не о чем.
Обрати внимание, нигде не упоминается ни вход в main(), ни начало main(). А о том как понимать, например, начало работы main() можно спорить до бесконечности. Ты будешь говорить, что вход в main() и есть начало работы main(), другой будет доказывать, что начало работы - это выполнение первой прописаной в main() инструкции, третий ещё что-нибудь. Если я правильно понял (если нет - поправь), то выделение памяти происходит при входе в main(), но до выполнения первой инструкции прописанной в main() в коде.

Добавлено через 10 минут
Цитата Сообщение от kravam Посмотреть сообщение
теперь-то распутался?
Нет. Получается, что локальный массив, объявленный в main(), ничем не отличается от динамического. И размер ему можно задавать во время выполнения программы, и жить он будет до конца программы, только память под ним нельзя освободить.

Добавлено через 4 минуты
Цитата Сообщение от kravam Посмотреть сообщение
На всё это компилятор ругается.
У меня даже это не скомпилирует:
C++
1
2
3
4
5
6
7
int main()
{
 int m = 10;
 int arr[m];
 
 return 0;
}
Подавай ему const int m = 10.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 09:29  [ТС]     С++ VLA и прочее... #36
Вот что в литературе.
Миниатюры
С++ VLA и прочее...   С++ VLA и прочее...   С++ VLA и прочее...  

С++ VLA и прочее...   С++ VLA и прочее...   С++ VLA и прочее...  

Jupiter
01.12.2012, 10:41
  #37

Не по теме:

Цитата Сообщение от MrGluck Посмотреть сообщение
Но gcc умеет корректно обрабатывать данные запросы, приводя к константе размер массива на момент создания. А учитывая, что никаких плохих последствий из этого не выходит, можно предположить, что данное поведение будет узаконено в будущих стандартах С++ (все же в стандарт С подобную фичу включили).
не надо нам VLA! это зло

kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,270
01.12.2012, 10:59     С++ VLA и прочее... #38
Цитата Сообщение от alsav22 Посмотреть сообщение
Обрати внимание, нигде не упоминается ни вход в main(), ни начало main(). А о том как понимать, например, начало работы main() можно спорить до бесконечности. Ты будешь говорить, что вход в main() и есть начало работы main(), другой будет доказывать, что начало работы - это выполнение первой прописаной в main() инструкции, третий ещё что-нибудь.
для того, чтобы узнать адрес функции, есть такой код:
C++
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
    printf ("%x\n", main);
    getchar ();
    return 0;
}
. Это адрес функции или, что то же самое, её начало. Адрес первой АССЕМБЛЕРНОЙ инструкции, если угодно. Я не буду спорить если кто-то скажет что нет, не это начало, на фиг надо нервы трепать.
...Кстати, да, вот тут Evg договорился до начала main. Видишь, я тоже поднимал (и поднимаю) подобные вопросы
Почему глобальный объект, объявленный до main, конструируется в ней?


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Цитата Сообщение от alsav22 Посмотреть сообщение
Если я правильно понял (если нет - поправь), то выделение памяти происходит при входе в main(), но до выполнения первой инструкции прописанной в main() в коде.
Нет. Мы входим в функцию main, мы никак не можем миновать первую инструкцию. Вот здесь чётко показано, вот функция main, она ограничена слева жирной скобкой.
http://www.cyberforum.ru/attachment....8&d=1354307130


1) Первая инструкция main Это PUSH EBP (подсвечена)
2) блаблабла
3) Инструкция, которая выделяет память SUB ESP, 34
4) блаблабла
5) Инструкция, которая кладёт в выделеную память строку "rrrrr....."REP MOVS BYTE блаблабла

Цитата Сообщение от alsav22 Посмотреть сообщение
Нет. Получается, что локальный массив, объявленный в main(), ничем не отличается от динамического. И размер ему можно задавать во время выполнения программы, и жить он будет до конца программы, только память под ним нельзя освободить.
Так и получается. Это скорее хорошо, чем плохо. Вот тут MrGluck попытался это объяснить
Порекомендуйте компилятор

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

На счёт всего остального- я не знаю что и сказать. Все пишут как "должно быть", но преподносят это "как есть". А его нет, сам же видел, оно просто должно быть. С другой стороны если по стандарту описано, что для "нединамических" массивов память должна быть известна заранее, авторы так и напишут, согласен? Вот и всё.
И кстати, тот же Стивен Прата (в той же книге "Статический класс памяти, внешнее связывание", таблица 9.1) определяет "статический" класс памяти не как "нединамический", а как либо объявленый с ключевым словом static, либо как объявленный вне функции, это то, о чём я написал в предыдущем посту и это то, чему не соответствует твоя цитата.
Порекомендуйте компилятор
Кто прав в этом случае я решил для себя. По-моему Прата убедительнее.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Как видишь, есть противоречия между всем и всем. Но что делать? Надо двигаться вперёд; где-то напролом, где-то как. Периодически возвращаясь к этому нерешённому вопросу, коих будет ещё очень много. Однажды решишь эти вопросы не абсолютно, но ДЛЯ СЕБЯ и скажешь:

"Колея это только моя, выбирайтесь своей колеёй".
В. Высоцкий.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 20:04  [ТС]     С++ VLA и прочее... #39
Цитата Сообщение от kravam Посмотреть сообщение
Это адрес функции или, что то же самое, её начало. Адрес первой АССЕМБЛЕРНОЙ инструкции, если угодно.
Это я понимаю. Я другую инструкцию имею ввиду. Цитирую себя:
Цитата Сообщение от alsav22 Посмотреть сообщение
Если я правильно понял (если нет - поправь), то выделение памяти происходит при входе в main(), но до выполнения первой инструкции прописанной в main() в коде.
Имею ввиду первую написанную инструкцию в исходнике. Например, код:
C++
1
2
3
4
5
6
7
int main()
{
    cout << "Entry;
    int m = 3;
    cout << m;
    return 0;
}
Выделение памяти произойдёт при входе в main() до выполнения первой инструкции в тексте кода:
C++
1
cout << "Entry;
Так?

Цитата Сообщение от kravam Посмотреть сообщение
И кстати, тот же Стивен Прата (в той же книге "Статический класс памяти, внешнее связывание", таблица 9.1) определяет "статический" класс памяти не как "нединамический", а как либо объявленый с ключевым словом static, либо как объявленный вне функции, это то, о чём я написал в предыдущем посту и это то, чему не соответствует твоя цитата.
Порекомендуйте компилятор
Кто прав в этом случае я решил для себя. По-моему Прата убедительнее.
Тут спорить не буду, просто повторю, что я имел ввиду не класс памяти, а употребляемое (не только мною) название для массива, размер которого известен (или должен быть известен (уже и не знаю, как писать)) на этапе компиляции. Слово одно, но в разных случаях - разные значния. Тот же Прата о статическом и динамическом связывании (скрин). Согласен, что путаница некая есть. Лучше, конечно, называть просто: локальный массив.
Миниатюры
С++ VLA и прочее...  
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.12.2012, 20:23     С++ VLA и прочее...
Еще ссылки по теме:

C++ Размер примитивных типов, выравнивание и прочее
Инкремент, декремент и прочее. A+++ - что означают это три плюса C++
C++ Рекурентная формула и прочее

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

Или воспользуйтесь поиском по форуму:
alsav22
01.12.2012, 20:23  [ТС]     С++ VLA и прочее...
  #40

Не по теме:

Прошу прощения, кавычки в коде пропустил. Не успел исправить.

Yandex
Объявления
01.12.2012, 20:23     С++ VLA и прочее...
Ответ Создать тему
Опции темы

Текущее время: 02:34. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru