Главное понять, что указатель на объект это не сам объект. И запомнить операции &, *, new, delete, а также привыкнуть к конструкциям типа int**&x
Кстати new уже морально устарела и ее обещают запретить в одной из следующих ревизий языка, но во всех книжках она пока что есть.
А адресная арифметика нужна только для жесткой оптимизации. Можно что угодно написать без нее.
Jame Bonds, мне вот интересно, то что уже прошел для того что бы начать писать на MQL5 хватит, или идти дальше не оглядываясь.
А так же DDL первую в жизни свою хочу, вкрутить в квик!
У меня там сейчас на qpile и lua всё
Борис Литвинов, чтобы писать на mql5 указатели могут и не понадобится. К тому же в mql указатели по синтаксису и идеологии ближе к объектам C#, а не к указателям С++.
Прочтите по диагонали справку по mql, она хорошо структурирована и похожа на учебник и в бой.
А чтобы написать dll лучше иметь знания поглубже, но это зависит от того, что dll делает.
Jame Bonds, буду делать парсинг на кластерный анализ. Вывод прямо в квик графика через lable. Нужна максимальная скорость парсинга, при чтении таблицы обезличенных сделок! по всему фронту!
Борис Литвинов, скинуть не смогу =)
я лейблами рисую прямоугольники на графике. За одну торговую сессию примерно 100 лейблов наносится на график. 3-4 торговых сессии и висяк конкретный. Приходится все очищать.
Борис Литвинов, на qlua + dll.
Сама фишка в том, что квик не может переварить столько лейблов на графике.
Я подумал что вы полный кластерный график будете наносить лейблами. Это подразумевает большое кол-во лейблов.
я в свое время делал для себя такой движок не на квике. Года 4 назад. Изначально выбрал тупиковый путь, убил пол года только зря. И закрыл проект =) Графика это вообще не мое
Андрей К, так что-то полезное из этого дела вынести смогли? Я вот тоже делаю свой гиперпродвинутый кластерный анализ, в том числе и стакана, но пока результатом похвастаться не могу, хотя есть определенный оптимизм. Но если бы я это все еще в графику переводил, это бы меня точно добило)) Так, в текстовом формате все сохранить разве что и на питоне представить в виде графиков. Но чтобы риалтайм все шуршало — это же сколько еще дополнительной работы! Тут еще самое стремное — это то, что не знаешь, не придется ли этот огромный пласт работы потом, по большому счету, выкинуть в мусорку…
ну я несколько лет торговал такой анализ. И хорошо очень заработал и хорошо спустил =)) Сейчас этот вид анализа уже давно в прошлом. Я это все дело достаточно сильно усовершенствовал и мне это все стало незачем.
Весь этот объемный анализ очень критичен к некоторым стадиям рынка. Меняется рынок (ну например ушли объемы с определенного фьюча), если трейдер не успевает перестроиться, это может стать критичным для него. Такая торговля, по крайней мере для меня, не очень.
Jame Bonds, мне вот интересно, то что уже прошел для того что бы начать писать на MQL5 хватит, или идти дальше не оглядываясь.
Борис Литвинов, вот-вот, оптимизм так и плещет через край!
Главный прикол здесь в том, что в MQL нет адресной арифметики.
А так же DDL первую в жизни свою хочу, вкрутить в квик!
У меня там сейчас на qpile и lua всё
Учебник неправильный. То, что ничего не падает, это просто везёт. Вот, можно посмотреть, какой мусор печатается вместо 10, 11, 12, 10 (наверху есть зелёная кнопочка Run, а также можно нажать F9).
Если бы было понимание адресной арифметики, то это было бы замечено сразу в исходном коде. Такие ошибки как раз и называют «переполнением буфера».
Но это — явные ошибки. А есть ещё неявные. Вот эта программа — неправильная. Факт того, что она печатает то, что и ожидается, означает, что нам просто везёт, потому что программа компилируется там ещё и без оптимизации. Стоит включить оптимизацию, и может произойти всё, что угодно, вплоть до падения.
Кстати, f1() специально написана на голом C, а f2(), которая делает в точности то же самое, — с использованием всего лишь нескольких специфических для C++ механизмов. Они не являются необходимыми, просто напихал слегка, чтобы дать хотя бы лёгкое представление о сложности «недетского» C++. В этой функции использовано явно меньше 1% всех имеющихся механизмов C++.
Именно поэтому я и предлагаю ограничиться голым C. Среди программистов-то, знающих голый C, трудно найти человека, который, хотя бы, более или менее знает C++.
Язык C — относительно (относительно!) небольшой, универсальный и достаточно низкоуровневый, чтобы исподволь сформировать также дополнительное понимание, как всё работает в компе. Позволит, в числе прочего, как писать свои DLL'ки, так и использовать его потом как неплохую базу для изучения других языков, если понадобится. Ну, или почти с нулевым усилием использовать, хоть и плюясь, MQL.
В приведённом примере есть выражение 256u**p+++*p++. Я специально записал его без пробелов, чтобы подчеркнуть «непростоту», обычно пробелы ставят, где надо.
Во-первых, как мне кажется, не каждый разберётся, что это тут такое понаписано. И буква u ещё какая-то затесалась… И, главное, это всё компилируется и работает...
Расставлю скобки: 256u * (*(p++)) + (*(p++)).
Суффикс u означает, что константа беззнаковая. Итак, 256 умножается на значение из первой «ячейки», указатель продвигается на следующую и к этому прибавляется значение из следующей ячейки, раз указатель до этого продвинулся, и указатель продвигается ещё раз.
Грубо говоря, в математическом виде это могло бы выглядеть так: sum = 256 * a[1] + a[2].
Теперь начинаются тонкости, почему программа неправильная.
Во-первых, подвыражения могут вычисляться в любом порядке, то есть, сначала может быть вычислена правая часть (*(p++)), а только потом левая 256u * (*(p++)). Это сделано для того, чтобы компилятор имел больше возможностей для оптимизации кода.
В данном случае математический эквивалент станет таким: sum = 256 * a[2] + a[1].
Потому что правое подвыражение же тоже продвигает указатель. Совершенно другой результат получается.
Более того, продвигание указателей может быть отложено на самый последний момент, и тогда математический эквивалент станет ещё интереснее: sum = 256 * a[1] + a[1].
Но это всё — ещё не самое страшное. Из-за этого всего просто результат был бы неправильным, и — всё. Звучит, — да, интересно. Просто неправильно вычисляется, а так — ничего страшного.
Но есть ещё кое-что. В этом самом выражении дважды происходит изменение одной и той же переменной (указателя p). А эта ситуация есть, так называемое, undefined behavior.
Страшная штука. Она означает следующее: при исполнении данного кода может быть всё, что угодно, от нормального выполнения, до условно, форматирования жёсткого диска. На практике, всё же, всё не так страшно: не до форматирования жёсткого диска, а, «всего лишь» до падения программы.
Причём, современные компиляторы при оптимизации используют этот undefined behavior в свою пользу: скорее всего, код, соответствующий этому выражению, будет просто выкинут. Причём, молча. Компилятор будет доволен: мощно соптимизировал.
И это всё ещё голый С, без всякого, там, C++.
А теперь вопрос: даёт ли тот «учебник» с неправильной программой, в которой «нахально торчит» неоднократное переполнение буфера, а также стиль обучения «по верхушкам» понимание вот этого всего?
Насколько легко «накодить» такого, вроде бы, «безупречного» кода, из-за которого программа будет падать?
Каковы шансы, обучившись «по верхушкам», хотя бы понять, из-за чего всё падает или неправильно вычисляется после включения оптимизации?
Надеюсь, я дал представление, насколько всё непросто, и сколько там всего. В том числе, не очевидного, тонкого и, на восприятие не программиста, мягко говоря, странного.
Jame Bonds, все эти рюшечки очень накладны по времени.
А если их еще внедрять в готовый проект, то весь тайминг алгоритмов может уехать очень сильно. Я поэтому по старинке =)
Главное понять, что указатель на объект это не сам объект.
Jame Bonds, этого понимания совершенно недостаточно для понимания адресной арифметики.
И запомнить операции &, *, new, delete, а также привыкнуть к конструкциям типа int**&x
А что делать, если после запоминания этих операций встретятся операции new[] и delete[]?
И — только я привыкну к конструкциям типа int **&x, как обязательно встретится что-нибудь этакое: int const volatile * const *volatile (&&x)[5], и — что мне тогда делать?
Тупая зубрёжка здесь не спасёт. Требуется понимание.
Кстати new уже морально устарела и ее обещают запретить в одной из следующих ревизий языка, но во всех книжках она пока что есть.
Эта статья на Хабре — за первое апреля, там даже среди прочих меток у статьи есть специальная метка «1 апреля». Операция new настолько фундаментальна для C++, что после её изъятия это будет уже совсем другой язык.
Тем не менее, можно писать очень сложные программы без единого использования операции new, но при этом вовсю используя динамическую память. Более того, именно так и полезно это делать.
C++ определяется не книжками, а стандартами. То, что в книжках, — это вторично. Компиляторы реализуют согласно стандарта, а не книжки.
А адресная арифметика нужна только для жесткой оптимизации.
Вот откуда это взялось?
Можно что угодно написать без нее.
Работа с массивами — уже адресная арифметика. Почему в C/C++ возможны конструкции типа 1[«No»]? Именно поэтому. Вот пример (наверху есть зелёная кнопочка Run, а также можно нажать F9). Если захочется поиграться, рядом с Run есть кнопочка Fork this. Можно будет редактировать исходник.
Опять же, если есть понимание, то выяснить, что это за чертовщина такая, &0[«Hell»], не составит никакого труда...
Вроде бы, простейшая программа, а, чтобы понять, почему она печатает «Hello!», довольно много тонкостей всяких знать надо.
Когда критикуют излишний оптимизм начинающих трейдеров, приводят пример, что инженерам, например, а, особенно, врачам довольно долго учиться надо, а потом ещё и практиковаться, прежде чем они что-то реальное смогут в своей области. И дальше задают вопрос, почему вы думаете, что в трейдинге не так?
Вот и с программированием такая же «петрушка». Причём, программирование уже стало в этом смысле «тяжелее» медицины.
Борис Литвинов, там вообще сплошные парадоксы и прочие квантовые эффекты наблюдаются.
Например, есть некий кусок кода с временем исполнения C, условно состоящий из двух «подкусков» кода с временами исполнения A и B. После «оптимизации» второго «подкуска» его время выполнения B уменьшается. Однако, при этом, при неизменном коде первого «подкуска» его время исполнения A увеличивается, причём сильнее, чем уменьшается время исполнения второго «подкуска» B.
В результате, в выражении C = A + B, при уменьшении B сумма C увеличивается. Потому что уменьшение B само по себе вызывает ещё большее увеличение A.
Видимо, с кешами процессора это связано. Код второго «подкуска» выталкивает данные из кеша, а это чрезвычайно дорого. Одна и та же инструкция может выполняться в десятки раз дольше, если данные не в кеше. Поэтому, если выполнение кода второго «подкуска» каждый раз выталкивает данные из кеша, необходимые для первого «подкуска», то неудивительно, что первый «подкусок» начинает выполняться медленнее, несмотря на то, что его код не менялся.
Так что ассемблер — это то, куда совершенно точно соваться не следует. Разве, что для развлечения.
А то что заинтересовались памятью, это путь к качественному росту =). Пригодится вам или нет в итоге, но это один из немногих путей для создания эффективных приложений. Но это уже когда счет идет на миллисекунды и гораздо ниже.
Андрей К, общаюсь с человеком у которого высоко нагруженный софт показывает феноменальные результаты. Именно по этому меня не пугают трудности. Хочу начать так писать
Багатенький Буратина, да, лишняя пара скобок еще никого беднее-болнее-мертвее не сделала, так что и
int b = *(pa++);
тоже имеет право на существование!
Багатенький Буратина, а, я просто привык уже с итераторами дело иметь, там хоть есть возможность проверить, вышел итератор за границы контейнера, или еще нет. А так, конечно, любой программист, который пишет большой проект будет плеваться при виде кода с указательной арифметикой и метками. Единственное, чем его можно оправдать — это если он используется локально, изолированно, в очень критичном месте.
Да, небольшое замечание от меня уже. Использование Console::WriteLine для отображения кириллицы — это хорошо, но оно лишает тебя одного большого преимущества: кроссплатформенности! Поэтому я бы посоветовал все таки найти способ использовать std::cout (std::wcout). Для этого, если я не ошибаюсь, достаточно в начале функции main() сделать вызов:
setlocale( LC_ALL, «russian_Russia.1251» );
вот не знаю, отработает ли это нормально под линукс, но под виндой — должно. По крайней мере, «сбербанк» в файл у меня оператором вставки ("<<") у меня пишется корректно.
Да, вот этот пример замечательно работает:
#include <iostream>
using namespace std;
int main()
{
setlocale( LC_ALL, «russian_Russia.1251» );
Из-за американских санкций индийские частные и государственные НПЗ отказываются принимать российскую нефть на крупных танкерах, сообщил Bloomberg. В феврале США ввели блокирующие ограничения против...
Тимур, а у Ирана уже неприятности
Amid concerns over rising winter demand, the government has launched the “2.0 Degrees Lower” campaign, encouraging households and industries to reduce heating te...
Bloomberg: G7 ищет способы ужесточить потолок цен на нефть из России
Страны Большой семерки (G7) разрабатывают меры, которые позволили бы обеспечить ужесточение потолка цен на нефть из России, пе...
Тимур Гайнетьянов, соглашусь с автором, проблема новатека лишь в том что там кто то за океаном решил искуственно емуспроблем создать, откровенно даже не маскирует свои намерения, но это все пройдет...
Вы тут все на своей волне веруя в хорошее вы упускаете меж рыночный анализ данных по Бензину Нафте Мазуту внимательно изучите данные нефть готовят к падению на 35 будьте аккуратны
Дмитрий Первый, если не научишься работать с риском, кроме щикотания нервов ничего не будет в торговле. Какие бы трейды не поймал, хоть +1000%. Итог будет один, я сам так много раз делал.
Кстати new уже морально устарела и ее обещают запретить в одной из следующих ревизий языка, но во всех книжках она пока что есть.
А адресная арифметика нужна только для жесткой оптимизации. Можно что угодно написать без нее.
А так же DDL первую в жизни свою хочу, вкрутить в квик!
У меня там сейчас на qpile и lua всё
Прочтите по диагонали справку по mql, она хорошо структурирована и похожа на учебник и в бой.
А чтобы написать dll лучше иметь знания поглубже, но это зависит от того, что dll делает.
у меня так сделано от 100 до 1000 лейблов. Зависает квик жуть как.
я лейблами рисую прямоугольники на графике. За одну торговую сессию примерно 100 лейблов наносится на график. 3-4 торговых сессии и висяк конкретный. Приходится все очищать.
Сама фишка в том, что квик не может переварить столько лейблов на графике.
Я подумал что вы полный кластерный график будете наносить лейблами. Это подразумевает большое кол-во лейблов.
Весь этот объемный анализ очень критичен к некоторым стадиям рынка. Меняется рынок (ну например ушли объемы с определенного фьюча), если трейдер не успевает перестроиться, это может стать критичным для него. Такая торговля, по крайней мере для меня, не очень.
Борис Литвинов, вот-вот, оптимизм так и плещет через край!
Главный прикол здесь в том, что в MQL нет адресной арифметики.
Учебник неправильный. То, что ничего не падает, это просто везёт. Вот, можно посмотреть, какой мусор печатается вместо 10, 11, 12, 10 (наверху есть зелёная кнопочка Run, а также можно нажать F9).
Если бы было понимание адресной арифметики, то это было бы замечено сразу в исходном коде. Такие ошибки как раз и называют «переполнением буфера».
Но это — явные ошибки. А есть ещё неявные. Вот эта программа — неправильная. Факт того, что она печатает то, что и ожидается, означает, что нам просто везёт, потому что программа компилируется там ещё и без оптимизации. Стоит включить оптимизацию, и может произойти всё, что угодно, вплоть до падения.
Кстати, f1() специально написана на голом C, а f2(), которая делает в точности то же самое, — с использованием всего лишь нескольких специфических для C++ механизмов. Они не являются необходимыми, просто напихал слегка, чтобы дать хотя бы лёгкое представление о сложности «недетского» C++. В этой функции использовано явно меньше 1% всех имеющихся механизмов C++.
Именно поэтому я и предлагаю ограничиться голым C. Среди программистов-то, знающих голый C, трудно найти человека, который, хотя бы, более или менее знает C++.
Язык C — относительно (относительно!) небольшой, универсальный и достаточно низкоуровневый, чтобы исподволь сформировать также дополнительное понимание, как всё работает в компе. Позволит, в числе прочего, как писать свои DLL'ки, так и использовать его потом как неплохую базу для изучения других языков, если понадобится. Ну, или почти с нулевым усилием использовать, хоть и плюясь, MQL.
В приведённом примере есть выражение 256u**p+++*p++. Я специально записал его без пробелов, чтобы подчеркнуть «непростоту», обычно пробелы ставят, где надо.
Во-первых, как мне кажется, не каждый разберётся, что это тут такое понаписано. И буква u ещё какая-то затесалась… И, главное, это всё компилируется и работает...
Расставлю скобки: 256u * (*(p++)) + (*(p++)).
Суффикс u означает, что константа беззнаковая. Итак, 256 умножается на значение из первой «ячейки», указатель продвигается на следующую и к этому прибавляется значение из следующей ячейки, раз указатель до этого продвинулся, и указатель продвигается ещё раз.
Грубо говоря, в математическом виде это могло бы выглядеть так: sum = 256 * a[1] + a[2].
Теперь начинаются тонкости, почему программа неправильная.
Во-первых, подвыражения могут вычисляться в любом порядке, то есть, сначала может быть вычислена правая часть (*(p++)), а только потом левая 256u * (*(p++)). Это сделано для того, чтобы компилятор имел больше возможностей для оптимизации кода.
В данном случае математический эквивалент станет таким: sum = 256 * a[2] + a[1].
Потому что правое подвыражение же тоже продвигает указатель. Совершенно другой результат получается.
Более того, продвигание указателей может быть отложено на самый последний момент, и тогда математический эквивалент станет ещё интереснее: sum = 256 * a[1] + a[1].
Но это всё — ещё не самое страшное. Из-за этого всего просто результат был бы неправильным, и — всё. Звучит, — да, интересно. Просто неправильно вычисляется, а так — ничего страшного.
Но есть ещё кое-что. В этом самом выражении дважды происходит изменение одной и той же переменной (указателя p). А эта ситуация есть, так называемое, undefined behavior.
Страшная штука. Она означает следующее: при исполнении данного кода может быть всё, что угодно, от нормального выполнения, до условно, форматирования жёсткого диска. На практике, всё же, всё не так страшно: не до форматирования жёсткого диска, а, «всего лишь» до падения программы.
Причём, современные компиляторы при оптимизации используют этот undefined behavior в свою пользу: скорее всего, код, соответствующий этому выражению, будет просто выкинут. Причём, молча. Компилятор будет доволен: мощно соптимизировал.
И это всё ещё голый С, без всякого, там, C++.
А теперь вопрос: даёт ли тот «учебник» с неправильной программой, в которой «нахально торчит» неоднократное переполнение буфера, а также стиль обучения «по верхушкам» понимание вот этого всего?
Насколько легко «накодить» такого, вроде бы, «безупречного» кода, из-за которого программа будет падать?
Каковы шансы, обучившись «по верхушкам», хотя бы понять, из-за чего всё падает или неправильно вычисляется после включения оптимизации?
Надеюсь, я дал представление, насколько всё непросто, и сколько там всего. В том числе, не очевидного, тонкого и, на восприятие не программиста, мягко говоря, странного.
https://habr.com/post/352570/
)
А если их еще внедрять в готовый проект, то весь тайминг алгоритмов может уехать очень сильно. Я поэтому по старинке =)
Jame Bonds, этого понимания совершенно недостаточно для понимания адресной арифметики.
А что делать, если после запоминания этих операций встретятся операции new[] и delete[]?
И — только я привыкну к конструкциям типа int **&x, как обязательно встретится что-нибудь этакое: int const volatile * const *volatile (&&x)[5], и — что мне тогда делать?
Тупая зубрёжка здесь не спасёт. Требуется понимание.
Эта статья на Хабре — за первое апреля, там даже среди прочих меток у статьи есть специальная метка «1 апреля». Операция new настолько фундаментальна для C++, что после её изъятия это будет уже совсем другой язык.
Тем не менее, можно писать очень сложные программы без единого использования операции new, но при этом вовсю используя динамическую память. Более того, именно так и полезно это делать.
C++ определяется не книжками, а стандартами. То, что в книжках, — это вторично. Компиляторы реализуют согласно стандарта, а не книжки.
Вот откуда это взялось?
Работа с массивами — уже адресная арифметика. Почему в C/C++ возможны конструкции типа 1[«No»]? Именно поэтому. Вот пример (наверху есть зелёная кнопочка Run, а также можно нажать F9). Если захочется поиграться, рядом с Run есть кнопочка Fork this. Можно будет редактировать исходник.
Опять же, если есть понимание, то выяснить, что это за чертовщина такая, &0[«Hell»], не составит никакого труда...
Вроде бы, простейшая программа, а, чтобы понять, почему она печатает «Hello!», довольно много тонкостей всяких знать надо.
Когда критикуют излишний оптимизм начинающих трейдеров, приводят пример, что инженерам, например, а, особенно, врачам довольно долго учиться надо, а потом ещё и практиковаться, прежде чем они что-то реальное смогут в своей области. И дальше задают вопрос, почему вы думаете, что в трейдинге не так?
Вот и с программированием такая же «петрушка». Причём, программирование уже стало в этом смысле «тяжелее» медицины.
Например, есть некий кусок кода с временем исполнения C, условно состоящий из двух «подкусков» кода с временами исполнения A и B. После «оптимизации» второго «подкуска» его время выполнения B уменьшается. Однако, при этом, при неизменном коде первого «подкуска» его время исполнения A увеличивается, причём сильнее, чем уменьшается время исполнения второго «подкуска» B.
В результате, в выражении C = A + B, при уменьшении B сумма C увеличивается. Потому что уменьшение B само по себе вызывает ещё большее увеличение A.
Видимо, с кешами процессора это связано. Код второго «подкуска» выталкивает данные из кеша, а это чрезвычайно дорого. Одна и та же инструкция может выполняться в десятки раз дольше, если данные не в кеше. Поэтому, если выполнение кода второго «подкуска» каждый раз выталкивает данные из кеша, необходимые для первого «подкуска», то неудивительно, что первый «подкусок» начинает выполняться медленнее, несмотря на то, что его код не менялся.
Так что ассемблер — это то, куда совершенно точно соваться не следует. Разве, что для развлечения.
Именно по этому меня не пугают трудности. Хочу начать так писать
надо наверное много куда потыкаться, чтобы найти свою тропинку
Сначала возвращается значение по указателю, потом инкремент адреса указателя.
(*pa)++ это инкремент значения по указателю.
int b = *(pa++);
тоже имеет право на существование!
setlocale( LC_ALL, «russian_Russia.1251» );
вот не знаю, отработает ли это нормально под линукс, но под виндой — должно. По крайней мере, «сбербанк» в файл у меня оператором вставки ("<<") у меня пишется корректно.
Да, вот этот пример замечательно работает:
Терпи!
Заглатывай!