Предложение по доработке функции DoubleToStr - страница 2

 
chv:
Кстати, я не видел в MQL (может, плохо искал) функции или константы-аналога DECIMALSEPARATOR в Delphi (в MS.NET это свойство NumberFormatInfo.NumberDecimalSeparator), т.е. узнать текущий системный разделитель нельзя, или я не прав?
Константы, аналогичной Delphi нету, но можно привлечь WinAPI:
#import "kernel32.dll"
  int GetSystemDefaultLCID();
  int GetLocaleInfoA(
    int    Locale,      // locale identifier
    int    LCType,      // type of information
    string lpLCData,    // address of buffer for information
    int    cchData      // size of buffer
  );
#import
 
int start() {
  int    LCID=GetSystemDefaultLCID();
  int    LOCALE_SDECIMAL=0x0000000E;
  string st=" ";
 
  GetLocaleInfoA(LCID, LOCALE_SDECIMAL, st, 1);
  Comment(st);
}
Вместо LOCALE_SDECIMAL можно вписать просто число 14. А вот LCID заменять на 1049 не стоит, потому что у кого-то может стоять нерусская версия винды, а с LCID'ом 1033 (английская), например. Поэтому LCID лучше получать соответствующей функцией.
 
KimIV:
А вот LCID заменять на 1049 не стоит, потому что у кого-то может стоять нерусская версия винды, а с LCID'ом 1033 (английская), например. Поэтому LCID лучше получать соответствующей функцией.

Вот-вот, у меня как раз English XP Pro Corporate. С учётом того, что сказал выше Ренат, и того, что .dll однозначно на всех чемпионатах зарубят, думаю этой версии DoubleToStr не суждено родиться :)
 
Ничего дорабатывать именно в таком ракурсе рассмотрения проблеммы не нужно, это реальные грабли, если вы правельно на это посмотрите, то увидите это, отдельные функции, которых будет как минимум две тоже никчему. У меня тоже идей много, однако если я ради каждой не полноценной идеи буду открывать здесь по теме, форум превратится в бардак. Но раз уж бардака не миновать, то и я отпишусь:)

Я вот здесь подумываю о .NET адаптере, правда размышления и эксперементы приводят к нагромождению кода в MQL, например получается необходимо таскать как минимум одно число дескриптора в каждой функции, чтобы обеспечить более менее прямой доступ к своей сборке, возврату и учету памяти распределенной не в MQL скрипте и не в управляемой памяти, например строк и массивов ну и примитивных типов которых всего несколько, по адресу. Плюс к тому несколько управляющих функций для инициализации и завершения контекста, да еще и стек параметров учитывать, не говоря о ступенчантом построении вызова. С одной стороны все красиво, исключения в отдельном окошке всякая дребедень для удобства рассмотрения, с другой стороны бороться с нагромождением непростая задача, не будешь же таскать по двадцать дескрипторов.

Например вызов статической функции из своего класса может выглядить следующим образом, естественно всем фреймеворком можно пользоваться без загрузки сборок.

#import "dotnetex.dll"
  bool DNXContextClear( int &rContext ); // Очистка контекста, необязательно, так как задействовано при инициализации методов.
  bool DNXContextClose( int &rContext ); // Завершает контекст.
 
  int DNXAssemblyHandleA( int &rContext, string iAssembly ); // Загружает сборку и/или возвращает дескриптор уже загруженной.
  bool DNXAssemblyReloadA( int &rContext, string iAssembly ); // Перезагружает сборку, если она была загружена возвращает дескриптор.
  bool DNXAssemblyRemoveA( int &rContext, string iAssembly ); // Удаляет связи сборки из текущего контекста.
  bool DNXAssemblyDeleteA( int &rContext, string iAssembly ); // Удаляет все связи сборки, полная дисфункция.
 
  bool DNXTypeInitA( int &rContext, string iType );
  bool DNXMethodInitA( int &rContext, string iMethod );
  bool DNXParamInt32( int &rContext, int iValue );
  bool DNXParamDouble( int &rContext, double iValue );
  bool DNXParamString( int &rContext, string iValue );
  int DNXResultInt32( int &rContext );
 
#import
 
int Context = 0;
 
int start() {
  DNXAssemblyHandleA(Context, "Test" );
  DNXTypeInitA(Context, "Test.MyClass" );
  DNXMethodInitA(Context, "MyTest" );
  DNXParamInt32(Context, 123);
  int ret = DNXResultInt32(Context);
  DNXContextClose(Context);
  return( ret );
}
но другой вопрос как это будет выглядеть в коде, прямо хоть в строках передавай и типы и функции а потом делай разборку, явное нагромождение получается если все делить по функциям, я уже не говорю о количестве кода в библиотеке для таких на первый взгляд простеньких операций, как говорится чем проще снаружи, тем сложнее внутри, поэтому я все еще размышляю как в этой ситуации можно придти к совершенству, не нарушая правила языка и имея возможность пользоваться всем. Сделать на подобие обработчиков XML строки разбирать. Но тогда нельзя играть параметрами и брать по адресу для ref или out, а может и то и другое написать, чтобы был выбор. Например:

#import "dotnetex.dll"
  bool DNXContextClear( int &rContext ); // Очистка контекста, необязательно, так как задействовано при инициализации методов.
  bool DNXContextClose( int &rContext ); // Завершает контекст.
 
  int DNXAssemblyHandleA( int &rContext, string iAssembly ); // Загружает сборку и/или возвращает дескриптор уже загруженной.
  bool DNXAssemblyReloadA( int &rContext, string iAssembly ); // Перезагружает сборку, если она была загружена возвращает дескриптор.
  bool DNXAssemblyRemoveA( int &rContext, string iAssembly ); // Удаляет связи сборки из текущего контекста.
  bool DNXAssemblyDeleteA( int &rContext, string iAssembly ); // Удаляет все связи сборки, полная дисфункция.
 
  int DNXCallInt32( int &rContext, string iValue );
  double DNXCallDouble( int &rContext, string iValue );
  string DNXCallString( int &rContext, string iValue );
 
#import
 
int Context = 0;
 
int start() {
  DNXAssemblyHandleA(Context, "Test" );
  int ret = DNXCallInt32(Context,StringConcatenate( "Test.MyClass.Testing(", 123, ")" ));
  DNXContextClose(Context);
  return( ret );
}
А может я вообще забью на реализацию универсальной библиотеки, для своих нужд гораздо проще экспортировать лишь стандартные функции с некоторой поддержкой стека параметров в контексте, для управления промежуточной памятью. Я то .NET воспользуюсь и без всех этих нагромождений, а вот душа хандрит, типа помогая себе не забудь помоч ближнему:) Тьфу, в итоге понимаешь в какие рамки приходится упираться когда под руками необъятные возможности, которые нельзя просто применить, взяв да и заюзав, нет, ради того чтобы поставить тот же ордер из вне, надо зацикливаться или проверять переключатели событий, короче думать можно бесконечно, а хотябы калбеков нехватает.

P.S.: Вот такая вот дребедень лезет в голову, а в итоге смысл теряется. .. Обходя слона, не забудь не раздавить мышку:) Так что совет вам да любовь в ваших изысканиях:)

P.P.S: Знания сила, но еще не гарантия успеха, в том или ином виде деятельности, поэтому мои знания технологий лишь мешают для простейшего программирования, а ведь когда-то, радовался при малейшем успехе или новым познаниям, новом обходе гимороя, который до этого небыл гимороем, в итоге, программирование стало инструментом, который не приносит радость как раньше, а чаще всего сводит мозг от невозможности воспользоваться изобилием всего возможного:) По простым причинам, то о чем сейчас задумаешься невозможно реализовать в одиночку, а для того чтобы что-то делать в команде, нужно сначала проявить значимость, а вот где она здесь, один бог знает, в итоге то все равно вернемся к тому с чего начали, так как не имея путь вперед, либо ищешь другие пути либо пользуешься тем что дают и не задаешь глупых вопросов:)

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

В остальном надеюсь что вам понравился мой маленький пост, хотя тема такая же бестолковая как и сам пост:)
 
xnsnet:

В остальном надеюсь что вам понравился мой маленький пост, хотя тема такая же бестолковая как и сам пост:)
Глубина и широта мысли впечатляет :-)
Вижу коллегу по замыслам. Вы никогда не пробовали решать такую задачу?
 
chv:
С учётом того, что сказал выше Ренат, и того, что .dll однозначно на всех чемпионатах зарубят, думаю этой версии DoubleToStr не суждено родиться :)
Чемпионат - это ещё не вся жизнь. А для себя-то мы решение всегда найдём.
Я тут поковырял эту тему дальше и обнаружил разные интересности, которые могут пригодиться. Импорт винапных функций и объявление констант сделал в отдельный модуль b-Locale.mqh. А для удобства использования сделал две функции GetSystemLocale и GetUserLocale. Вот несколько примеров использования одной из них:

Аббревиатура первого дня недели: для Россиян Пн
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SABBREVDAYNAME1));
}
Национальное название шестого дня недели, для Россиян "суббота":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SDAYNAME6));
}
Наименование десятого месяца, для Россиян "Октябрь":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SMONTHNAME10));
}
Короткое наименование восьмого месяца, для Россиян "авг":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SABBREVMONTHNAME8));
}
Разделитель списка, для Россиян ";":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SLIST));
}
Разделитель даты, для Россиян ".":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SDATE));
}
Разделитель времени, для Россиян ":":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_STIME));
}
Короткий формат даты, для Россиян "dd.MM.yyyy":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SSHORTDATE));
}
Длинный формат даты, для Россиян "d MMMM yyyy г.":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_SLONGDATE));
}
Формат времени, для Россиян "H:mm:ss":
#include <b-Locale.mqh>
int start() {
  Comment(GetSystemLocale(LOCALE_STIMEFORMAT));
}

Luptator:
Можно оставить функцию DoubleToStr() как есть и добавить ещё одну версию этой функции, которая чувсвтительна в системному разделителю, только назвать назвать по-другому, к примеру DoubleToStrF(). Да и все. Кто хочет юзает, кто не хочет -нет.:)

:-) сказано - сделано. Только назвал я её DoubleToStrLocale. Параметры те же, что и у родительской функции DoubleToStr. Код новой функции находится в библиотеке b-Locale.mqh и вот пример её использования:

#include <b-Locale.mqh>
int start() {
  Comment(DoubleToStrLocale(1.23456789, 6));
}
У меня возвращается строка "1,234568".
Файлы:
b-locale_1.mqh  22 kb
 
KimIV, спасибо.
 
Меня вот интересует другое, кстати хорошо что есть такой пример, как реализован учет памяти в MT4, надеюсь что строки не учитываются по длинне до нуля, иначе благодаря такогому коду образуется утечка памяти, так как распределен один буфер, а выгружается другой, более коротки, врочем если из кучи не выгружается ничего до завершения всего стека вызовов, например для этого используется отдельная куча, которая потом разом выгружается. Я пока так и не понял как реализовано управление памятью в скрипте, если бы мне кто подсказал, был бы очень признателен! Неприятно когда основываешь свою теорию на догадках.

Не вяжется определение локальных переменных переменных, с таким примером кода, так как судя из успеха этой функции, для строк не используется стек, а используется память из кучи, которая либо изначально предопределена, что при повторном вызове гарантирует буферу предопределенные значения с момента приведущего вызова. И этот тест это подтверждает, но на основе этого выводов не сделаешь. Хотя я могу сказать что для всего стека вызовов выделяется память один раз. И я уже вижу ошибку, повторный вызов, приводит уменьшению длинны буфера для GetLocaleInfoA а значит любой повторный вызов в одном и том же коде приведет к неисправности. Поэтому акцентирую внимание KimIV на этом участке, используйте число размера буфера, а не функцию StringLen

string GetSystemLocale(int LCType) {
  int    loc=GetSystemDefaultLCID();
  string str="                                                                ";
  GetLocaleInfoA(loc, LCType, str, 64);
  return(str);
}
Это будет правельным, а вот так я нашел эту дырочку:

#import "kernel32.dll"
  int GetSystemDefaultLCID();
  int GetUserDefaultLCID();
  int GetLocaleInfoA(
    int    Locale,      // locale identifier
    int    LCType,      // type of information
    string lpLCData,    // address of buffer for information
    int    cchData      // size of buffer
  );
#import
 
int test = 0;
int GetSystemLocale(int LCType) {
  int    loc=GetSystemDefaultLCID();
  string str="                                                                ";
  int    len=StringLen(str);
 
  if ( test == 0 ) { GetLocaleInfoA(loc, LCType, str, len); test = 1; return (len); }
  return (len);
}
 
 
int start() {
    Print( GetSystemLocale( 0x0020 ) );
    Print( GetSystemLocale( 0x0020 ) );
    return(0);
}
 
xnsnet:
Меня вот интересует другое, ..., как реализован учет памяти в MT4, надеюсь что строки не учитываются по длинне до нуля, иначе благодаря такогому коду образуется утечка памяти, так как распределен один буфер, а выгружается другой, более коротки,...
Интересный вопрос.
Для проверки Вашего предположение по поводу утечки я сделал скриптик, в котором в бесконечном цикле вызываю функцию GetSystemLocale() с разным параметром LCType.
#include <b-Locale.mqh>
int start() {
  int    i=1;
  string s;
  while (true) {
    s=GetSystemLocale(i);
    i++; if (i>79) i=0;
  }
}
Запускал этот скрипт и в диспетчере задач следил за расходом памяти процессом terminal.exe. Утечек памяти не обнаружил, но в процессе изменений кода и наблюдения наткнулся на кое-что интересное. Оказывается при многократных вызовах одной и той же функции память под локальные переменные больше не выделяется. Например, если в начале многократно вызываемой функции я задам локальную строковую переменную размером 64 символа, а в процессе обработки размер строки сократится, то при следующих вызовах этой же функции я не смогу восстановить размер строки до 64 символов. Этот эффект наглядно демонстрирует следующий код:
#include <b-Locale.mqh>
int start() {
  int    i=79;
  string s;
  while (true) {
    s=GetSystemLocale(i);
    Comment("i=",i,"  s=",s,StringLen(s));
    Sleep(100); i--; if (i<1) i=79;
  }
}
Обратите внимание, что переменная s в начале одного размера, а потом постепенно вырождается в строку нулевой длины.
 
xnsnet, дописывание постов путает. Лучше пишите следующий пост.
 
xnsnet:
И я уже вижу ошибку, повторный вызов, приводит уменьшению длинны буфера для GetLocaleInfoA а значит любой повторный вызов в одном и том же коде приведет к неисправности.
Да, Вы правы, так и есть. Я тоже это обнаружил.

xnsnet:
Поэтому акцентирую внимание KimIV на этом участке, используйте число размера буфера, а не функцию StringLen

string GetSystemLocale(int LCType) {
  int    loc=GetSystemDefaultLCID();
  string str="                                                                ";
  GetLocaleInfoA(loc, LCType, str, 64);
  return(str);
}
Благодарю за конструктив :-)
Причина обращения: