Учу C++ и разбирая один проект наткнулся на то что автор часть функций (основных) реализовал на MASM, а очень плохо разбираюсь в MASM, и в интернете ничего толком не нашёл по этой теме. Можете кто-нибудь перевести эти 3 функции в C++, с комментариями что да как? Дальше я уже сам разберусь.
Сам код на MASM (исходник, заголовочный файл):
RES equ 52
HED equ 16
;normalizace [edi] - mantisa nebude zaинnat ani konиit na nulu
;zmмnн esi,edi
norm proc
cmp dword ptr [edi-12],0
jbe @@ret ;zlomek nebo nula
call trim
mov ecx,[edi-12]
test ecx,ecx
jz @@ret ;trim vэsledek vynulovalo
xor edx,edx
cmp [edi],edx
jnz @@ret
mov eax,edi
@@lp: add eax,4
dec dword ptr [edi-4]
jo @@nul
dec ecx
jz @@nul
cmp [eax],edx
jz @@lp
@@e: mov esi,eax
mov [edi-12],ecx
cld
rep movsd
@@ret: ret
@@nul: mov dword ptr [edi-12],0
ret
norm endp
@NORMX@4: mov eax,ecx
@normx proc uses esi edi
mov edi,eax
call norm
ret
@normx endp
;alokuje инslo s mantisou dйlky eax
@ALLOCX@4: mov eax,ecx
@allocx proc
push eax
lea eax,[eax*4+HED+RES] ;vиetnм hlaviиky a rezervovanйho mнsta
push eax
call Alloc ; вызывает функцию из C++ - void *Alloc(int size) { return operator new(size); }
pop edx
pop ecx
test eax,eax
jz @@ret
add eax,HED
mov [eax-16],ecx
mov dword ptr [eax-12],0 ;inicializuj na nulu
mov dword ptr [eax-4],1
mov dword ptr [eax-8],0
@@ret: ret
@allocx endp
ALLOCN:
ALLOCNX proc
mov eax,[esp+8]
lea eax,[eax*4+HED+RES] ;vиetnм hlaviиky a rezervovanйho mнsta
push eax
mul dword ptr [esp+8]
push eax
call Alloc
pop edx
pop ecx
test eax,eax
jz @@ret
lea eax,[eax+edx+HED]
@@lp:
sub eax,ecx
mov edx,[esp+8]
mov [eax-16],edx
mov dword ptr [eax-12],0 ;inicializuj na nulu
mov dword ptr [eax-4],1
mov dword ptr [eax-8],0
mov edx,[esp+4]
mov edx,[esp+4*edx+8]
mov [edx],eax
dec dword ptr [esp+4]
jnz @@lp
@@ret: ret
ALLOCNX endp
А в C++ они записаны как:
Pint __fastcall ALLOCX(Tint len); // Allocate number (len is in Tint units), initialize to zero, return pointer to mantissa
Pint __cdecl ALLOCN(int n, Tint len, ...); // Allocate n numbers, vararg are variables for pointers
void __fastcall NORMX(Pint x); // Normalize mantissa
Буду признателен.
Базовая структура (описана в заголовочном файле arith.h):
struct Numx {
Tint
alen, //allocated data length (in Tint units)
len, //used data length (in Tint units), 0=zero, -1=variable, -2=fraction, -5=range, -12=matrix
sgn, //sign 0=plus,1=minus
exp, //exponent (how many Tints has integer part)
m, //mantissa, (most significant digits are at the beginning)
d,
reserved[12];
};
Это по сути заголовок и зарезервированные поля. Размер этой структуры (6 + 12)*4 = 72
байта, что равно HED + 4 байта мантиссы + RES
. Выделяется структура и дополнительный блок данных функцией ALLOCX
:
Pint __fastcall ALLOCX(Tint len);
// Allocate number (len is in Tint units), initialize to zero, return pointer to mantissa
Функция выделяет память нужного размера, делает инициализацию заголовка, возвращает указатель на мантиссу (поле m внутри структуры).
Смысл примерно такой:
Pint ALLOCX(Tint len) {
Numx * numx = alloc(sizeof(Numx) + sizeof(Tint)*(len-1));
numx->alen = len; // [eax-16]
numx->len = 0; // [eax-12]
numx->exp = 1; // [eax-4]
numx->sgn = 0; // [eax-8]
return &(numx->m); // eax
}
Это не подстрочный перевод ассемблерного кода, это именно как оно работает.
В процедуре NORMX
наоборот принимается указатель на мантиссу. Если переводить на Си, то по-хорошему нужно из этого указателя вычислить указатель на начало структуры, и дальше работать через имена полей, а не через смещения, как в ассемблерном варианте.
Я бы вообще переделал процедуры, чтобы они работали через указатель на начало структуры, а не указатель на мантиссу. Это вообще довольно странное решение, выгода такого решения не очень понятна.
Ниже добавил подстрочный перевод процедуры norm
(мог где-то ошибиться, нужно тестировать):
#ifndef BYTE
typedef char BYTE;
#endif
// mantisa nebude začínat ani končit na nulu // Мантисса не будет начинаться или заканчиваться на ноль
void NORMX(Pint x) {
// Костыль ниже нужен, чтобы из указателя на мантиссу получить указатель на начало структуры
struct Numx * numx = 0;
size_t HED = (BYTE*)&(numx->m) - (BYTE*)numx; // Для 32-битного кода получится 16
numx = (Numx*)((BYTE*)x - HED);
// cmp dword ptr [edi-12],0 ; len
// jbe @@ret ;zlomek nebo nula
if(numx->len <= 0) return; // zlomek nebo nula // дробь или ноль
// call trim // uříznutí koncových nul [edi] // обрезать конечный нуль [edi]
trim(x);
// mov ecx,[edi-12] ; len
// test ecx,ecx
// jz @@ret ;trim výsledek vynulovalo
Tint len = numx->len;
if(len == 0) return; // trim výsledek na nulu // обрезать результат до нуля
// xor edx,edx // edx = 0
// cmp [edi],edx
// jnz @@ret
if(numx->m != 0) return;
// mov eax,edi
Pint p = &(numx->m);
do {
// @@lp: add eax,4
p++;
// dec [dword edi-4]
// jo @@nul
Tint new_exp = numx->exp - 1;
if(new_exp > numx->exp) { // переполнение
numx->len = 0;
return;
}
numx->exp = new_exp;
// dec ecx
// jz @@nul
len--;
if(len == 0) {
numx->len = 0;
return;
}
// cmp [eax],edx
// jz @@lp
} while(*p == 0);
// @@e: mov esi,eax
// mov [edi-12],ecx ; len
numx->len = len;
// cld
// rep movsd ; [dword edi] = [dword esi], edi++, esi++, ecx+=4
for(Pint edi=&(numx->m); len>0; len--, edi++, p++)
*edi = *p;
}
Pint - это видимо int *; ALLOCX тогда делает вот, что:
#define HED 4
#define RES 13
Pint ALLOCX(Tint len)
{
int *iptr = new int[len + HED + RES];
if(!iptr)
return 0;
iptr += HED;
iptr[-4] = len;
iptr[-3] = 0;
iptr[-1] = 1;
iptr[-2] = 0;
return iptr;
}
остальное я думаю можно понять и так
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня есть функция которая вызывается отдельным потоком и поток отделяется:
Задание: необходимо реализовать ИИ при игре в крестики-нолики на джавеСамый первый шаг рандомный выбор ячейки и проверка соседних ячеек...
Выводит эти значения, но RUB,PLN,JPY,DKK и так дальше, не форматированы