Форум программистов, компьютерный форум, киберфорум
Nexi99
Войти
Регистрация
Восстановить пароль
Рейтинг: 5.00. Голосов: 1.

Функции общего назначения

Запись от Nexi99 размещена 02.06.2021 в 00:54
Обновил(-а) Nexi99 Вчера в 05:27

Возможно мои записи в блоге будут перенесены на Хабр а здесь будут ссылки на ресурсы.
Я разрабатываю функции, задача которых эффективно управлять данными, в частности речь идёт о работе с массивами и указателями. Здесь я буду выставлять свои разработки которые будут спрятаны в dll если они очень дороги. Функции будут модифицированы со временем и могут измениться. На данный момент я выставляю динамическую библиотеку т.к. со статической физически нет времени возиться.
Прошу обратить внимание код моих функций универсальный но типы опциональны т.к. у меня нету разных процессоров чтобы подобрать универсальные типы.char(1)short(2)int(4)long long(8)
Чтобы получить данные к некоторым массивам и функциям подключите библиотеку Nexi99 находится в архиве к сожалению есть пока 32 битная версия т.к. собирал на отладке, к ому же мне приходится направлять адреса на аргументы функций и в 64 битных такое не работает т.к. там аргумента ложатся в регистры.
C++
1
HMODULE hLib=LoadLibraryA("Nexi99.dll");
Создайте дескриптор и загрузите библиотеку в вашу программу. Библиотека может находиться по пути:
там где находится exe-ый вашей программы, в папке system(возможно 32ой), либо укажите путь при заполнении строки аргумента LoadLibraryA в кавычках.
Чтобы выгрузить библиотеку используйте запись
C++
1
FreeLibrary(hLib);
. Т.е. как вы поняли вы можете использовать отложенную загрузку и выгрузку библиотек, в нужный момент подключаемся и отключаемся.
У меня есть заголовочный файл #include "Modul.h"
его код
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define Ch char
#define Sh short
typedef unsigned Sh unshort;
#define USh unshort
#define I int
#define L long
#define Fl float
#define Db double
typedef long long datetime;
#define Dt datetime
#define udt unsigned long long
#define ret return
#define N NULL
#define en endl
#define el2 T,P
#define nam1        typename T
#define nam2  nam1, typename P
#define templ(T)      template<nam1>
#define templ2(el2)   template<nam2>
#define McH1 templ (T) 
#define McH2 templ2(el2)
Когда у функции много аргументов или у типов длинные названия или команды это очень удобно.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define bites_ (sizeof(Dt)+3)*sizeof(Dt)+3-1
char*bits_=(char*)GetProcAddress(hLib,"bits_");//100000000 8589934592
//все найденные значение должны быть меньше на 1цу или использовать знак <
unsigned L L*ter=(unsigned L L*)&bits_[2];char*ter_=(char*)&ter[sizeof(Dt)];
void Maks_Znah(){double qq[3];unsigned L L op[2]={10};ter[0]=ter[sizeof(Dt)+1]=1;//ter[7]-9223372036854775808/18446744073709551616-1//для стандартных процессоров
char w[5]={1,1};for(;(w[0]=w[0]<<1);)w[1]++;bits_[1]=(bits_[0]=w[1])*sizeof(Dt);//узнаём сколько бит в байте w[1]
ter[0]=(1<<(w[1]-1))*2;w[2]=w[1]+1;
*ter_=w[3]=Zifra_(ter[0]);
for(char t=1;++t<w[3];)op[0]*=10;
for(char t=0;++t<w[1];){ter[t]=ter[t-1];
for(char q=0;++q<w[2];){
if(!(op[1]=ter[t]<<1))break;ter[t]=op[1];//
if(!w[4]){*qq=op[1]*1.0;
if(*qq==op[1]){qq[1]=*qq;ter[sizeof(Dt)+1]*=Zifra(op[1],ter[sizeof(Dt)+1]);
qq[1]/=(ter[sizeof(Dt)+1]*10);
if(!(w[4]=(bool)((Dt)(qq[1]*(ter[sizeof(Dt)+1]*10))!=ter[t])))qq[2]=*qq;}}}//находим максимальное значение для double
ter_[t]=(ter_[t-1]-1+(w[3]=Zifra_d(ter[t],op[0])));for(char e=0;++e<w[3];)op[0]*=10;}
bits_[bites_]=Zifra_t(ter[sizeof(Dt)+2]=qq[2],ter[sizeof(Dt)+1]/=10);}
Массив bits_ имеет размер bites_+1. 0ой индекс хранит количество бит в байте. Как вы видите из кода используется универсальный алгоритм подсчёта бит в байте а не константа 8 как это сделано у разработчиков. 1ый индекс хранит количество бит учитывая максимальный тип поддерживаемый вашим процессором у меня это 64.
Массив ter имеет размер sizeof(Dt)+3 хранит в своих ячейках значения которые можно вместить в указанное количество байт. Например ter[0] у меня выдаёт 256 и так пока не закончится заполнение максимального количества байт. По индексу ter[sizeof(Dt)+1] хранится экспонента на которую можно разделить максимальное значение типа double.
По индексу ter[sizeof(Dt)+2] хранится мантисса,если считать выше то идут искажения. Если доживу сделаю свой double с большим диапазоном. Если поставить значение ter[sizeof(Dt)+2] в цикл то его можно немного увеличить.По координатам bits_[bites_] записана длина мантиссы в символах смотрите ниже.
Массив ter_ имеет размер sizeof(Dt). В своих ячейках он хранит длину значения в символах. Например ter[0]=256 что даёт 3 символа.
Функции по определению длины значения.
C++
1
2
3
4
5
Dt Zifra(Dt zn,Dt tel=0){Dt h=1;if(tel)zn/=tel;for(;zn/=10;)h*=10;ret h;}//функция возводит 10 в степень пока не закончится число
char Zifra_(Dt zn){Dt h=1;for(;zn/=10;)h++;ret h;}//функция просматривает число и возвращает его длину в 
//символах(например 256 содержит 3 символа)или степень в которую можно возвести 10ку
char Zifra_d(Dt zn,Dt tel){Dt h=0;h+=(bool)(zn/=tel);for(;zn/=10;)h++;ret h;}//работает как и предыдущая за исключением что //можно ослабить число выражением zn/=tel; возвращает смещение
char Zifra_t(Dt zn,Dt tel){Dt h=(zn/=tel)+(bool)zn;for(;zn/=10;)h++;ret h;}//работает как и предыдущая а также похожа на //Zifra_ возвращает количество символов числа
Функции Zifra_d и Zifra_t предназначены для того чтобы уменьшить количество итераций цикла, за это отвечает аргумент tel. Если этот аргумент будет заполнен то к примеру функция Zifra_d вернёт частичную длину значения. Например у нас есть число 2568. Если мы знаем что изначально число содержало 3 символа
то функцию Zifra_d нужно вызвать так
C++
1
Zifra_d(2568,1000);
результатом этой функции будет 1ца, прибавляем её к 3ке потому что 1000 это 10 в 3ей степени и изначально мы знаем об этом, и получаем 4ку т.е. наше число имеет 4 символа. Функции очень полезны для написания таймеров и других подобных модулей.

Функции по нахождению размера массива(опциональны по типам).
Создайте указатели на функции, объявите переменную int*bytes, объявите и вызовите функцию
C++
1
void funkz(int q=0){*bytes=(int)&q;}
а также направьте указатели на функции и переменные используя GetProcAddress
C++
1
2
3
int(*ArrayRange0)(...);int(*ArrayRange1)(int);//указатели на функции которые будут находить размер динамического массива
#define ArrayRange_Mk0(q) ArrayRange0(q)/sizeof(q)
#define ArrayRange_Mk1(q) ArrayRange1((int)q)/sizeof(q)
C++
1
2
3
4
5
6
7
8
9
(FARPROC&)bytes=GetProcAddress(hLib,"bytes");
(FARPROC&)ArrayRange0=GetProcAddress(hLib,"ArrayRange0");
(FARPROC&)ArrayRange1=GetProcAddress(hLib,"ArrayRange1");
//вызов функций
int*arr=new int[12];*arr=456;
cout<<"*arr "<<*arr<<en;
arr[1]=ArrayRange_Mk0(arr);
arr[2]=ArrayRange_Mk1(arr);
cout<<"размер массива "<<arr[1]<<" "<<arr[2]<<en;
Теперь объясню как это всё работает. Переменная *bytes направлена на последний аргумент функции, т.е. она хранит адрес стэка где лежат аргументы функции. Мы запоминаем номер байта вызовом функции funkz,
из которого можно извлекать значение. Функция ArrayRange0 может быть использована как шаблонная, т.е. её можно экспортировать в другой ЯП. Единственный нюанс это то что переменная *bytes должна попадать по координатам нужного вам элемента. В с++ действует правило что если у функции 1ин аргумент то он ложиться в конец стэка аргументов функции, а функция использует единый максимальный блок памяти для хранения аргументов а также переменных объявленных внутри неё. Т.е. это один массив распиленный на 2 части, аргументы считываются отдельно справа налево, а переменные тоже считываются отдельно, но адресное пространство у них одно. Смотрите пример ниже.
C++
1
2
3
void funkz1(int q,int q1){...}
void funkz2(int q2){...}
void funkz2(char q3){char w; char e; Dt y;}
По примеру этих функций результат такой: q3 q2 q1 будут находиться по адресу *bytes. y и q3 будут находиться рядом в одном и том же массиве что и аргументы функции. Все функции которые вы запустите будут использовать одну и ту же область памяти как массив. При выходе из функции массив освобождается при входе заполняется. Компилятор автоматически выделит статическую память чтобы туда поместились все переменные и аргументы. Нет возможности экспортировать шаблоны но можно сделать так. Но не во всех ЯП *bytes будет указывать на последний аргументы иногда нужно указатель смещать например в mql4. Подробности опишу позже если доживу. В С++ это работает надёжно.
Вызов функции ArrayRange0 должен производиться таким образом чтобы было понятно что элемент попадает в стэк по адресу *bytes. Например.
C++
1
2
3
4
5
6
7
funkz1(ArrayRange0(arr),ArrayRange_Mk0(arr))//правильно
arr[1]=ArrayRange_Mk0(arr);//правильно
arr[ArrayRange_Mk0(arr)];//правильно
cout<<ArrayRange0(arr)<<en;//неправильно
//объявим и вызовем функцию
int funt_(int q){...ret q};
funkz1(ArrayRange0(arr),funt_(ArrayRange_Mk0(arr)));//правильно
В строке 4 мы не попадаем на адрес *bytes, потому что внутри cout раскрывается много модулей и классов и на эту позицию ложиться куча переменных и понятное дело что мы теряем доступ к элементу, а функция ArrayRange0, не может получить адресацию т.к. принимает аргумент неизвестного типа, самое главное чтобы его размер был равен размеру указателя, а также считывание должно происходить по адресу *bytes, если происходит сдвиг то в функцию должен быть вписан алгоритм который будет координировать переменную *bytes чтобы вы могли считывать любые данные и имитировать шаблоны. Функция ArrayRange0 приобретает универсальность. В инструкции майкрософт написано что 4 аргумента ложаться в регистры, я не знаю насколько это так, судя по комментариям ниже у меня собралась 32 битная библиотека.

Если не работает функция ArrayRange0, то используйте функцию ArrayRange1, но в неё нужно передавать тип int и как вы уже поняли она теряет универсальность, но её можно вызывать как угодно и в cout в том числе. Обе функции возвращают размер в байтах если память выделялась оператором new, поэтому я дописал макрос который делит размер на тип ячейки, если вы используете maloc то размер массива использовать макрос не нужно. Размер статического массива не записывается ни куда ведь никто его менять не будет.
Вложения
Тип файла: rar Nexi99.rar (9.3 Кб, 100 просмотров)
Размещено в Без категории
Показов 1501 Комментарии 19
Всего комментариев 19
Комментарии
  1. Старый комментарий
    Похоже, сбилось разбиение на строки в некоторых примерах кода.
    Запись от politoto размещена 02.06.2021 в 08:15 politoto вне форума
  2. Старый комментарий
    Аватар для _lunar_
    Цитата:
    Сообщение от politoto Просмотреть комментарий
    Похоже, сбилось разбиение на строки в некоторых примерах кода.
    это тяжелый случай.
    я ему уже объяснял, что нужно писать код в читабельном виде, но товарищ уперся рогом в стену и продолжает её долбить.
    Запись от _lunar_ размещена 02.06.2021 в 19:44 _lunar_ на форуме
  3. Старый комментарий
    Аватар для Алексей1153
    предлагаю действия по улучшению кода:
    1) дефайны убрать
    2) добавить форматирование
    3) покрасить
    4) выбросить
    5) использовать std::vector

    Запись от Алексей1153 размещена 02.06.2021 в 19:49 Алексей1153 вне форума
  4. Старый комментарий
    Цитата:
    Сообщение от Алексей1153 Просмотреть комментарий
    предлагаю действия по улучшению кода:
    1) дефайны убрать
    5) использовать std::vector
    используйте вектора я что нашёл то частично и написал. Да и к тому же некоторые вещи без дефайнов не сделаешь чтобы было поменьше проверок.
    Запись от Nexi99 размещена 02.06.2021 в 20:03 Nexi99 вне форума
    Обновил(-а) Nexi99 02.06.2021 в 20:05
  5. Старый комментарий
    Аватар для Алексей1153
    Цитата:
    некоторые вещи без дефайнов не сделаешь чтобы было поменьше проверок.
    например?
    Запись от Алексей1153 размещена 02.06.2021 в 20:07 Алексей1153 вне форума
  6. Старый комментарий
    Цитата:
    Сообщение от Алексей1153 Просмотреть комментарий
    например?
    Ребята не обижайтесь.Я спорить с вами не буду здесь. В темах где вопросы задаю пишите что хотите. Здесь макрос я использовал для удешевления кода у меня нет времени писать километровые коды, я лучше сделаю что-то полезное.
    Запись от Nexi99 размещена 02.06.2021 в 20:14 Nexi99 вне форума
  7. Старый комментарий
    Аватар для Avazart
    Цитата:
    для удешевления кода у меня нет времени писать километровые коды, я лучше сделаю что-то полезное.
    Используйте вектор и будет Вам удешевление и без необходимости использовать макросы.

    Действительно полезным было бы тщательнее изучать С++ и перестать чудокодить.
    Запись от Avazart размещена 03.06.2021 в 00:12 Avazart на форуме
    Обновил(-а) Avazart 03.06.2021 в 00:14
  8. Старый комментарий
    Цитата:
    В инструкции майкрософт написано что 4 аргумента ложаться в регистры, я не знаю насколько это так вполне возможно что создаётся копия иначе адрес аргумента функции взять было бы не возможно.
    Для x64 по майкрософтовскому стандарту первые аргументы действительно передаются через регистры:
    C
    1
    2
    3
    4
    5
    6
    
    __declspec(dllexport)
    int m( int a, int b ){
     
            int * pa = &a, * pb = &b;
            return a + 4 * b;
    }
    Windows Batch file
    1
    
    cl /c /O1 m.c /Faconout$ /FAsc
    Код:
    a$ = 8
    b$ = 16
    m       PROC                                            ; COMDAT
    ; 3    :
    ; 4    :        int * pa = &a, * pb = &b;
    ; 5    :        return a + 4 * b;
    
      00000 8d 04 91         lea     eax, DWORD PTR [rcx+rdx*4]
    
    ; 6    : }
      00003 c3               ret     0
    m       ENDP
    Код, вызывающий функцию, обязан перед вызовом функции выделить в стеке область, куда вызываемая функция может сохранять аргументы.
    Но вызываемая функция не обязана что-либо сохранять в эту область.

    В нашем примере компилятор сгенерировал такой код из 2 инструкций:

    C
    1
    2
    
    eax = rcx + 4 * rdx; // LEA     eax, DWORD PTR [rcx+rdx*4]
    return; // RET
    На x32(x86) - зоопарк всевозможных конвенций.
    Запись от politoto размещена 03.06.2021 в 08:24 politoto вне форума
  9. Старый комментарий
    Цитата:
    Сообщение от politoto Просмотреть комментарий
    Для x64 по майкрософтовскому стандарту первые аргументы действительно передаются через регистры:
    Это понятно. Я смотрел инструкции которые вы мне в темах передавали. Этот стек как выяснилось можно и менять, по умолчанию Майкрософт даёт 2мб памяти под него, если память используется не вся там даже можно массивы выделять прямо на статической памяти и не обязательно использовать new для этого. И как выяснилось направить туда указатель тоже можно. Значит по тем инструкциям указано что мой процессор тоже ложит аргументы в регистры. Но возникает вопрос почему берутся адреса на аргументы функций если данные находятся в регистрах, значит либо не все процессоры ложат данные в регистры несмотря на то что он 64 битные, либо создаётся копия потому что стэк под инструкции функции же создан в статической памяти создан. Вы функцию вызвали вызвали а значит объём памяти используете.
    Я точно не знаю прокатит ли у всех эта функция int(*ArrayRange0)(...) поэтому сделал вторую, да и к тому же если по тому адресу будет положено что-то ещё то доступ теряется.
    Запись от Nexi99 размещена 03.06.2021 в 18:44 Nexi99 вне форума
  10. Старый комментарий
    Цитата:
    Сообщение от politoto Просмотреть комментарий
    Код, вызывающий функцию, обязан перед вызовом функции выделить в стеке область, куда вызываемая функция может сохранять аргументы.
    Но вызываемая функция не обязана что-либо сохранять в эту область.
    Память выделяется на этапе сборки сразу под самую большую функцию и эта область постоянна я выяснил это угробив месяцы времени на эксперименты. Я управляю последним аргументов вручную используя вариативную функцию поэтому данные и сохраняются.
    Запись от Nexi99 размещена 03.06.2021 в 18:48 Nexi99 вне форума
  11. Старый комментарий
    Но вот только одно интересно почему у меня на 64-ом процессоре берётся адрес на аргумент функции. Значит копия создаётся либо в регистры не загружаются данные.
    Запись от Nexi99 размещена 03.06.2021 в 18:50 Nexi99 вне форума
  12. Старый комментарий
    А у Вас разве 64-разрядная DLL?
    Windows Batch file
    1
    
    link /dump /headers Nexi99.dll /nologo
    Код:
    Dump of file Nexi99.dll
    
    PE signature found
    
    File Type: DLL
    
    FILE HEADER VALUES
                 14C machine (x86)
                   7 number of sections
            60B6A9C3 time date stamp Wed Jun  2 02:42:27 2021
                   0 file pointer to symbol table
                   0 number of symbols
                  E0 size of optional header
                2102 characteristics
                       Executable
                       32 bit word machine
                       DLL
    
    OPTIONAL HEADER VALUES
                 10B magic # (PE32)
    Запись от politoto размещена 04.06.2021 в 07:54 politoto вне форума
  13. Старый комментарий
    Цитата:
    Сообщение от politoto Просмотреть комментарий
    А у Вас разве 64-разрядная DLL?
    Да. Но модель процессора давно устарела. Возможно стоит сделать статическую библиотеку но я не знаю как толком их делать. Задача не приоритетная хотя есть. Я так понял это ошибка какае та?
    Запись от Nexi99 размещена 04.06.2021 в 21:32 Nexi99 вне форума
  14. Старый комментарий
    Цитата:
    Сообщение от Nexi99 Просмотреть комментарий
    . Возможно стоит сделать статическую библиотеку но я не знаю как толком их делать. Задача не приоритетная хотя есть.
    И для чего Вам нужна статическая библиотека, тоже толком не знаете?

    Цитата:
    Я так понял это ошибка какае та?
    Если DUMPBIN не ошибается, то Вы собрали корректную DLL для использования в 32-разрядных приложениях Windows на машинах с архитектурой x86. Единственная проблема в том, что Ваша DLL зависит от отладочной MSVCRT*, которая есть только у тех, кто установил себе Visual Studio 2012.
    Можно ли убрать зависимость MSVCRT* или в целом она не мешает?
    На 64-ой модели работать это всё не будет т.к. у меня много что повязано на памяти и адресах, а компилятор будет ложить данные в регистры, поэтому я даже не знаю смогу ли я это переделать на 64 версию.
    Как прочитать данные из регистров если компилятор их ложит туда?
    Будут ли в 32-ом коде работать регистровые переменные, или компилятор всё равно проигнорирует такую переменную с ключевым словом register?
    Я так понимаю что если часть аргументов в регистрах то памяти в стэке уже выделяется меньше на 4 элемента каждый по 4 байта?
    Запись от politoto размещена 05.06.2021 в 05:27 politoto вне форума
    Обновил(-а) Nexi99 06.06.2021 в 01:48
  15. Старый комментарий
    Цитата:
    Сообщение от politoto Просмотреть комментарий
    И для чего Вам нужна статическая библиотека, тоже толком не знаете?

    Если DUMPBIN не ошибается, то Вы собрали корректную DLL для использования в 32-разрядных приложениях Windows на машинах с архитектурой x86. Единственная проблема в том, что Ваша DLL зависит от отладочной MSVCRT*, которая есть только у тех, кто установил себе Visual Studio 2012 или ту, версию, которая у Вас. И оптимизация, скорее всего, отключена. Компилятор расставлял кучу кода для удобства отладчика, но этот код не нужен для нормальной работы DLL.

    Чтобы из среды Visual Studio собрать 64-разрядную DLL для установки на другие машины, нужно переключить конфигурацию с Debug Win32 на Release x64 или что-то подобное.
    Ну у меня да такая 12 студия, 98ой стандарт про эти настройки когда-то 5 лет назад читал но уже не помню как его настраивать.
    А где переключать эту настройку? Я помню когда с этим возился долго.
    Статическая библиотека позволит экспортировать классы которые там. Да и к тому же если я правильно понял они сразу встраивают это дело в код, а динамическая просто будет занимать память ради нескольких функций а их там может быть вагон. Я если доживу экспортирую класс и через динамическую библиотеку по частям чтобы подключать к другим оболочкам, но со статическими хотелось бы поработать и найти по ним комплексный материал, как я в письме вам писал.
    Запись от Nexi99 размещена 05.06.2021 в 06:02 Nexi99 вне форума
  16. Старый комментарий
    А в обычных условиях эту настройку нужно включать? Я так понимаю 64 ые придают многопоточность и другие свойства и в целом позволяют использовать процессор эффективнее?
    Запись от Nexi99 размещена 05.06.2021 в 06:04 Nexi99 вне форума
  17. Старый комментарий
    Обычно на главной панели инструментов есть комбобокс Debug/Release ( и другие конфигурации, которые есть в solution ). Рядом обычно выпадающий список для выбора архитектуры машины.

    Собрать 64-разрядное приложение можно и в 32-разрядной системе, но запустить - только в 64-разрядной для той же архитектуры(x64 или arm64), которая была выбрана при сборке.
    Для 32-разрядных приложений x86 64-разрядная Windows эмулирует 32-разрядную среду Windows для x86.
    Запись от politoto размещена 05.06.2021 в 06:31 politoto вне форума
  18. Старый комментарий
    Цитата:
    Сообщение от Nexi99 Просмотреть комментарий
    Статическая библиотека позволит экспортировать классы которые там. Да и к тому же если я правильно понял они сразу встраивают это дело в код.
    Почему бы Вам не встроить классы в код без использования дополнительных библиотек?
    Статические библиотки позволяют заранее откомпилировать код, который не меняется, сложить объектные файлы в архив и затем подавать их на вход компоновщика для сборки бинарников ( файлов EXE, DLL, SYS etc. в windows )
    Когда вы используете для сборки MSBuild ( в Visual Studio ), make и подобные утилиты, они и так отслеживают файлы, которые изменились с последней попытки сборки, чтобы не компилировать лишнее.
    Запись от politoto размещена 05.06.2021 в 06:43 politoto вне форума
    Обновил(-а) politoto 05.06.2021 в 06:48
  19. Старый комментарий
    Когда 64-разрядное приложение работает в 64- разрядной системе, процессор работает в режиме, для которого он спроектирован. А 32-разрядные режимы совместимости позволяют использовать без перекомпиляции софт, разработанный в 1990-е.
    Запись от politoto размещена 05.06.2021 в 06:52 politoto вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.