Есть программа на паскале, написанная изначально не мной.
Перевожу ее на C#. В одной из части программы идет весьма своеобразный расчет контрольной суммы файлов. Контрольная сумма хранится в базе в формате bigint и функция расчета контрольной суммы выглядит так:
function GetCheckSum(FileName: string): DWORD;
var
F: file of DWORD;
P: Pointer;
Fsize: DWORD;
Buffer: array[0..500] of DWORD;
begin
FileMode := 0;
AssignFile(F, FileName);
Reset(F);
Seek(F, FileSize(F) div 2);
Fsize := FileSize(F) - 1 - FilePos(F);
if Fsize > 500 then
Fsize := 500;
BlockRead(F, Buffer, Fsize);
Close(F);
P := @Buffer;
asm
XOR eax, eax
XOR ecx, ecx
mov edi, P
@again:
add eax, [edi + 4 * ecx]
inc ecx
cmp ecx, Fsize
jl @again
mov @result, eax
end;
end;
Подскажите, что происходит в Ассемблере и как бы могла выглядеть данная конструкция в C#?
Воспользовался следующим:
private long GetCheckSum(string FilePath)
{
byte[] FBytes = File.ReadAllBytes(FilePath);
int FSize = FBytes.Length / 2;
int FToRead = FSize + 500 > FBytes.Length ? FBytes.Length : FSize + 500;
long FSum = 0;
for (int i = FSize; i < FToRead; i++)
{
FSum += FBytes[i];
}
return FSum;
}
На мой взгляд получилось идентично. Поправьте, если я не прав.
Просто сумма 32-разрядных беззнаковых чисел (по модулю 2^32, если возникнет переполнение).
UInt32 buffer[500];
sum = 0;
for (i = 0; i < fsize; i++)
sum += buffer[i];
Файл читается как бинарный, суммирование осуществляется для чисел из второй половины файла (благодаря Seek), их количество не превышает 500. Т.о. для размера файла 8000 байт (2000 чисел) прочитаны будут числа с номерами от 1000 по 1499. Для размера файла 800 байт (200 чисел) прочитаны будут числа с номерами от 100 по 199.
Пояснения на c-подобном псевдокоде
XOR eax, eax // DWORD eax = 0; // здесь будет храниться результат
XOR ecx, ecx // int ecx = 0; // будет работать как индекс
mov edi, P // DWORD * edi = buffer;
@again:
add eax, [edi + 4 * ecx] // eax += edi[ecx]; // На ассемблере *4 потому что размер элемента 4 байта
inc ecx // ecx++;
// if(ecx<Fsize) goto again;
cmp ecx, Fsize
jl @again
mov @result, eax // result = eax;
Сделал так:
private long GetCheckSum(string FilePath)
{
byte[] FBytes = File.ReadAllBytes(FilePath);
int FSize = FBytes.Length / 2;
int FToRead = FSize + 500 * 4 > FBytes.Length ? FBytes.Length : FSize + 500 * 4;
long FSum = 0;
for (int i = FSize; i < FToRead; i += 4)
{
FSum += BitConverter.ToUInt32(FBytes, i);
}
return FSum;
}
Вроде как, возвращает то, что надо. BitConverter.ToUInt32 конвертирует 4 байта в массиве с указанной позиции в 32-битное беззнаковое число. Сама функция GetCheckSum читает последовательность байтов из файла. Узнает где середина файла и начиная с нее перебегает через максимум 2000 элементов (если столько есть) с шагом 4. То есть по факту максимум 500 шагов. С помощью функции BitConverter.ToUInt32 получает сумму беззнаковых чисел и возвращает ее.
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости