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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.89
alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
#1

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

30.11.2012, 00:17. Просмотров 1390. Ответов 51
Метки нет (Все метки)

 Комментарий модератора 
Перенесено из Порекомендуйте компилятор


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;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.11.2012, 00:17
Здравствуйте! Я подобрал для вас темы с ответами на вопрос С++ VLA и прочее... (C++):

Скремблирование и прочее - C++
Добрый день, помогите разобраться. Нужно написать программу для скремблирование файлов. Но перед этим вопрос: как из исходного файла...

Рекурентная формула и прочее - C++
Добрый день , пишу вам для получения помощи! Никак не могу сделать рекурентную формулу и программу под выражением &quot;б&quot;Помогите...

Дирректива define и прочее - C++
Помогите пожалуйста решить задание, никогда раньше с такими не сталкивался! =( 1) Даны целые числа x, у и вещественное число z....

Указатель на массив char и прочее - C++
Страуструп для проверки прочитанного в заданиях после одной из глав просит через typedef сделать пару объявлений и вот как делать некоторые...

Стиль написания кода(читабельность и прочее) - C++
Недавно делал тестовое задание для поиска работы, но мне сказали, что код не совсем корректно написан. Задание:Написать рекурсивный и не...

Размер примитивных типов, выравнивание и прочее - C++
Как обычно борются с тем, что примитивный тип от компа к компу разного размера? Допустим, если записывают данные по сети или в двоичные...

51
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
30.11.2012, 21:36 #16
Пришла пора расставить всё на свои места.

Цитата Сообщение от alsav22 Посмотреть сообщение
Неправильно кажется. Память в стеке, под переменные, выделяется до начала работы main(). В этом всё и дело. Как выделить память, если размер её неизвестен?
посмотрел твою цитату; кто такое пишет ему руки надо оторвать, цитату можно понимать двояко (а нужно чтобы она понималась ОДНОЗНАЧНО).

Давай всё-таки разделим мухи отдельно, котлеты отдельно. Есть понятие "выделение стека", а есть понятие "выделение памяти в стеке."На самом деле по твоей цитате речь идёт первом, то есть программе выделяется кусок памяти и говорится: "это стек, запихивай туда свои данные". Иначе и быть не может. Но можно предположить и второй вариант (мою версию выделения памяти)- так уж она скользко написана.

Цитата Сообщение от alsav22 Посмотреть сообщение
Как выделить память, если размер её неизвестен?
Это если предполагать, что память под локальные переменные выделяется до начала main (твои предположения);а если она выделяется в процессе main, то всё становится на свои места.

Поэтому смотрим своими глазами где что и как выделяется, поехали:


Проверяем, вот код:
C++
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
using namespace std;
 
int main()
{
    int m= 0X5555666;
    printf ("%x\n", m);
    getchar ();
    return 0;
}
Так ты говоришь, память под переменную m выделится до начала main? запускаем прогу в отладчике, вот на нулевом рисунке ясно показана программа В НАЧАЛЕ РАБОТЫ, в правом нижнем углу СТЕК и я стрелками показал, что в стеке нет НИЧЕГО ПОХОЖЕГО на 0X5555666

Но, может быть, значения нет, а ячейка памяти выделена? Ни фига подобного, трассируем до момента, когда значение 0x55556666 будет занесено в стек, вот эта инструкция (ris_1.), я на неё показываю стрелкой, кроме того мы видим, что стек с начала работы охренительно увеличился и только ПОСЛЕ ВЫПОЛНЕНИЯ ЭТОЙ ИНСТРУКЦИИ в стек будет положено значение 0X5555666; куда именно я указал пятью восклицательными знаками.

Ну и наконец последняя картинка (ris_2) это мы видим что по адресу в стеке 0X22ff4C РЕАЛЬНО положилось значение 0X5555666 и случилось это непосредственно перед вызовом printf, а далеко не перед началом работы main; ну то есть вышло так: сперва выделена ячейка памяти, через некоторое время (не сразу) туда занесено значение 0X5555666
0
Миниатюры
С++ VLA и прочее...   С++ VLA и прочее...   С++ VLA и прочее...  

alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.11.2012, 22:54  [ТС] #17
Цитата Сообщение от kravam Посмотреть сообщение
Так ты говоришь, память под переменную m выделится до начала main?
Это не только я говорю, и не один я говорю. Многие говорят. Не раз, и не два встречал. Например, здесь: Размер статического массива
0
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
30.11.2012, 23:27 #18
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Место под все локальные переменные выделяется перед выполнением кода функции. Сколько этого места понадобится
А чё сказать? Я показал на пальцах, что место под локальную переменную m выделилось В ПРОЦЕССЕ выполнения кода, а не перед. Но чел убеждён что "перед". Ну пусть так и будет, мне-то что.

Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
когда его инициализировать, решает компилятор
с этим согласен

Добавлено через 9 минут
НЕ поленился щас вот такой код глянуть:
C++
1
2
3
4
5
6
#include <stdio.h>
int main()
{
    char arr[]= "rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr";
    return 0;
}
Да. Всё так и есть. В начале main стек мал и пуст. А где-то в середине программы стек УВЕЛИЧИЛСЯ и перегоняет туда эту строку. (Ставил нардварный бряк на этой строке в секции данных и смотрел, когда к ней будет обращение); могу скриншоты скинуть.
0
Герц
01.12.2012, 00:04
  #19

Не по теме:

C++
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
using namespace std;
 
int main()
{
    int m= 0X5555666;
    printf ("%x\n", m);
    getchar ();
    return 0;
}
Большой знаток C++ пришел :-D
using namespace std; и ни одного C++ заголовка.

0
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 00:05 #20
А ничего, что в стеке хранятся не только записи активаций функций, а и вагон с тележкой другой лабуды вроде записей активаций системных вызовов и SEH-фреймов, и кто-то должен за ними убирать, чтобы user-функции не напоролись на то, что им видеть не положено?
0
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
01.12.2012, 00:08 #21
Добавлено через 19 секунд
Цитата Сообщение от Герц Посмотреть сообщение
Большой знаток C++ пришел :-D
using namespace std; и ни одного C++ заголовка.
ну и чё? забыл убрать, пойти застрелиться с позора...

Добавлено через 1 минуту
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
А ничего, что в стеке хранятся не только записи активаций функций, а и вагон с тележкой другой лабуды вроде записей активаций системных вызовов и SEH-фреймов, и кто-то должен за ними убирать, чтобы user-функции не напоролись на то, что им видеть не положено?
пусть там хранится всё что угодно. Надо знания подгонять под факты, а не наоборот. Если ваши знания противоречат тому, что вы видите, можно тыщу раз пересматривать, в надежде увидеть что-то другое. А я бы усомнился в своих знаниях.
0
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 00:29 #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-код?
0
Миниатюры
С++ VLA и прочее...  
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
01.12.2012, 00:39 #23
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
И в отладчике main() выглядит так же (см. аттач). Что я делаю не так? Может, смотрю в main() начиная с её настоящей точки входа, а не чёрти знает куда в системный boilerplate-код?
Ну и чё дальше? Я увидел, что в регистр EBX кладётся адрес строки, скорее всего она лежит в секции данных. Ну и чё? Возьми с полки пирожок. Я так-то до хрена чё в отладчике вижу, я же не волоку сюда всё, что ни попадя.
0
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 00:49 #24
А SUB ESP, 0x34 после формирования EBP-фрейма и сохранения регистров такой незаметная, что капец.
0
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
01.12.2012, 00:55 #25
А понял тебя, базара нет, был неправ, бряк ставил не туда, если ты про это.

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

Если ты хочешь сказать, что стек увеличится имено инструкцией SUB ESP, 34- кто же спорит? Эта инструкция выполнилась в main, что и требовалось доказать. Стек увеличивается в main. Да, так. Я с самого начал а это говорил. Ну и? Жду дальнейших разоблачений.
0
MrGluck
Модератор
Эксперт CЭксперт С++
7418 / 4533 / 673
Регистрация: 29.11.2010
Сообщений: 12,287
01.12.2012, 00:58 #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.
1
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
01.12.2012, 01:04 #27
Память выделяется в прелюдии подпрограммы. Инициализация проводится после выделения. Обе части расположены между точкой входа и ret, так что в принципе "в теле функции". Полезный код main() (инициализация того массива) начинается уже после прелюдии, в этом смысле память выделяется до выполнения полезного кода main(), но, естественно, после входа в call main. /discuss
0
kravam
быдлокодер
1697 / 884 / 45
Регистрация: 04.06.2008
Сообщений: 5,482
01.12.2012, 01:10 #28
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Память выделяется в прелюдии подпрограммы
Я тоже могу сказать слово какое-нибудь, например "эпиграф функции" или "закат функции" и ждать, может собеседник подза..ся значение слов выяснять

Выделение памяти под массив и его инициализация происходят между точкой входа и ret, значит в main остальное- суета сует и томление духа. И давай уже завязывать.
0
alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
01.12.2012, 01:26  [ТС] #29
Всё. Окончательно запутался. Если выделение памяти под статический массив происходит во время работы программы, то зачем компилятору знать его размер?
0
MrGluck
Модератор
Эксперт CЭксперт С++
7418 / 4533 / 673
Регистрация: 29.11.2010
Сообщений: 12,287
01.12.2012, 01:31 #30
Цитата Сообщение от alsav22 Посмотреть сообщение
Всё. Окончательно запутался. Если выделение памяти под статический массив происходит во время работы программы, то зачем компилятору знать его размер?
Надо ж знать, сколько выделить.
0
01.12.2012, 01:31
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.12.2012, 01:31
Привет! Вот еще темы с ответами:

Инкремент, декремент и прочее. A+++ - что означают это три плюса - C++
день добрый х) в задании попалась такая операция: a+++ = b%2 так вот. что, собственно, означают это три плюса?я знаю что есть инкремент, но...

Для чего нужны переменные, и прочее типа, константа, типы , массивы и т.к.д ? - C++
Для чего нужны переменные, и прочее типа, константа, типы , массивы и т.к.д

Для чего нужно писать в int main() в скобках всякие args потом объявлять переменные, и прочее. Для чего если можно в сборках это все обьявлять. - C++
Для чего нужно писать в int main() в скобках всякие args потом объявлять переменные, и прочее. Для чего если можно в сборках это все...

Связка БД и прочее - MS Access
Здравствуйте. Я впервые занимаюсь БД и мне хотелось бы узнать, как осуществить следующее: Например создание БД для железнодорожных касс....


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

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

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