генерация рандомных чисел и запись их в файл в ассемблере
У меня есть программа, в которой я создаю нужный мне файл file.dat, и дальше хочу записать туда 20 рандомных чисел. Пока что я только создал файл и в цикле у меня успешно генерируются числа которые по очереди каждый раз возвращаются в регистр eax. И я знаю, что при записи в файл мне нужен будет какой то например bufforNumbers, в котором будут записаны все цифры, так вот, как мне в эту переменную записать все 20 чисел, что бы каждая предыдущая сохранялась в переменной. Вот мой код сейчас:
.586P
.MODEL flat, STDCALL
;--- stale z pliku .\include\windows.inc ---
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11
GENERIC_READ equ 80000000h
GENERIC_WRITE equ 40000000h
CREATE_NEW equ 1
CREATE_ALWAYS equ 2
OPEN_EXISTING equ 3
OPEN_ALWAYS equ 4
TRUNCATE_EXISTING equ 5
FILE_FLAG_WRITE_THROUGH equ 80000000h
FILE_FLAG_OVERLAPPED equ 40000000h
FILE_FLAG_NO_BUFFERING equ 20000000h
FILE_FLAG_RANDOM_ACCESS equ 10000000h
FILE_FLAG_SEQUENTIAL_SCAN equ 8000000h
FILE_FLAG_DELETE_ON_CLOSE equ 4000000h
FILE_FLAG_BACKUP_SEMANTICS equ 2000000h
FILE_FLAG_POSIX_SEMANTICS equ 1000000h
FILE_ATTRIBUTE_READONLY equ 1h
FILE_ATTRIBUTE_HIDDEN equ 2h
FILE_ATTRIBUTE_SYSTEM equ 4h
FILE_ATTRIBUTE_DIRECTORY equ 10h
FILE_ATTRIBUTE_ARCHIVE equ 20h
FILE_ATTRIBUTE_NORMAL equ 80h
FILE_ATTRIBUTE_TEMPORARY equ 100h
FILE_ATTRIBUTE_COMPRESSED equ 800h
FORMAT_MESSAGE_ALLOCATE_BUFFER equ 100h
FORMAT_MESSAGE_IGNORE_INSERTS equ 200h
FORMAT_MESSAGE_FROM_STRING equ 400h
FORMAT_MESSAGE_FROM_HMODULE equ 800h
FORMAT_MESSAGE_FROM_SYSTEM equ 1000h
FORMAT_MESSAGE_ARGUMENT_ARRAY equ 2000h
FORMAT_MESSAGE_MAX_WIDTH_MASK equ 0FFh
FILE_BEGIN equ 0h ;MoveMethod dla SetFilePointe
FILE_CURRENT equ 1h ;MoveMethod dla SetFilePointe
FILE_END equ 2h ;MoveMethod dla SetFilePointe
;--- funkcje API Win32 z pliku .\include\user32.inc ---
CharToOemA PROTO :DWORD,:DWORD
;--- z pliku .\include\kernel32.inc ---
GetStdHandle PROTO :DWORD
ReadConsoleA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
WriteConsoleA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ExitProcess PROTO :DWORD
wsprintfA PROTO C :VARARG ;; int wsprintf(LPTSTR lpOut,// pointer to buffer for output
;; LPCTSTR lpFmt,// pointer to format-control string
;; ... // optional arguments );
lstrlenA PROTO :DWORD
GetCurrentDirectoryA PROTO :DWORD,:DWORD
;;nBufferLength, lpBuffer; zwraca length
CreateDirectoryA PROTO :DWORD,:DWORD
;;lpPathName, lpSecurityAttributes; zwraca 0 jeœli b³ad
lstrcatA PROTO :DWORD,:DWORD
;; lpString1, lpString2; zwraca lpString1
CreateFileA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
;; LPCTSTR lpszName, DWORD fdwAccess,
;; DWORD fdwShareMode, LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate,
;; DWORD fdwAttrsAndFlags, HANDLE hTemplateFile
lstrcpyA PROTO :DWORD,:DWORD
;;LPTSTR lpString1 // address of buffer, LPCTSTR lpString2 // address of string to copy
CloseHandle PROTO :DWORD
;; BOOL CloseHandle(HANDLE hObject)
WriteFile PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
;; BOOL WriteFile(
;; HANDLE hFile, // handle to file to write to
;; LPCVOID lpBuffer, // pointer to data to write to file
;; DWORD nNumberOfBytesToWrite, // number of bytes to write
;; LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
;; LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O
;;);
ReadFile PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
;;BOOL ReadFile(
;;HANDLE hFile, // handle of file to read
;;LPVOID lpBuffer, // address of buffer that receives data
;;DWORD nNumberOfBytesToRead, // number of bytes to read
;;LPDWORD lpNumberOfBytesRead, // address of number of bytes read
;;LPOVERLAPPED lpOverlapped // address of structure for data
;;);
CopyFileA PROTO :DWORD,:DWORD,:DWORD
;; BOOL CopyFile(
;;LPCTSTR lpExistingFileName, // pointer to name of an existing file
;;LPCTSTR lpNewFileName, // pointer to filename to copy to
;;BOOL bFailIfExists // flag for operation if file exists
;;);
GetLastError PROTO
GetTickCount PROTO
;--- z pliku ..\include\masm32.inc ---
nseed PROTO :DWORD
nrandom PROTO :DWORD
dwtoa PROTO dwValue:DWORD, lpBuffer:DWORD ;dwtoa convert a DWORD value to an ascii string.
;dwtoa proc dwValue:DWORD, lpBuffer:DWORD
atodw PROTO lpBuffer:DWORD ;atodw converts a decimal string to dword.
;atodw proc String:PTR BYTE
StripLF PROTO :DWORD ;StripLF is designed to remove the CRLF (ascii 13,10) by writing an ascii zero in the place of the first occurrence of ascii 13.
;StripLF proc strng:DWORD
StdIn PROTO :DWORD,:DWORD ;StdIn receives text input from the console and places it in the buffer required as a parameter. The function terminates when Enter is pressed.
;StdIn proc lpszBuffer:DWORD,bLen:DWORD
StdOut PROTO :DWORD ;StdOut will display a zero terminated string at the current position in the console.
;StdOut proc lpszText:DWORD
;--- funkcje
;------------s
;includelib .\lib\user32.lib
;includelib .\lib\kernel32.lib
;includelib .\lib\masm32.lib
;-------------
_DATA SEGMENT
folderName BYTE "/newFolder", 0
fileName BYTE "/file.dat", 0
buffor BYTE 250 dup(0)
randomNumber DD ?
bufforNumbers DD 250 dup(0)
_DATA ENDS
;------------
_TEXT SEGMENT
main proc
; -- creating folder "newFolder" --
push OFFSET buffor
push 255
call GetCurrentDirectoryA
push OFFSET folderName
push OFFSET buffor
call lstrcatA
push 0
push OFFSET buffor
call CreateDirectoryA
; -- end --
; -- creating file "file.dat" --
push OFFSET buffor
push 255
call GetCurrentDirectoryA
push OFFSET fileName
push OFFSET buffor
call lstrcatA
push 0
push 0
push CREATE_ALWAYS
push 0
push 0
push GENERIC_WRITE
push OFFSET buffor
call CreateFileA
; -- end --
; -- generating random numbers --
call GetTickCount
push eax
call nseed
mov ecx, 20
generateRandomNumbers:
push ecx
;--- generating random numbers from 0 to 99 ---
push 99
call nrandom
mov bufforNumbers, eax
pop ecx
loop generateRandomNumbers
; -- end --
push 0
call ExitProcess
main endp
_TEXT ENDS
END
Ответы (2 шт):
Сбрось все числа в стек и получишь "временную" строку, а потом передай указатель на нее в функцию записи в файл.
В вашем коде 90% лишнего.
Если вы получаете рандом тиками, тогда лучше заменить вызов функции на инструкцию RDTSC, которая подразумевает "Read Time Stamp Counter", т.е. по сути делает то-же самое. Эта инструкция возвращает 64-бит тики в пару EDX:EAX. Обычно старшая часть счётчика в EDX переполняется долго, зато младшую часть в EAX вполне можно использовать как пародию на рандом. Чтобы увеличить рассеиваемость, можно в цикле крутить биты внутри регистра посредством ROL, а в качестве счётчика сдвигов задействовать сам-же счётчик цикла. Примитивно работать с файлами удобно через группу функций _lcreate() из kernel32.dll - они поддерживаются вплоть до систем х86-64 Win7-10.
Вот пример вашей задачи на FASM'e.
Здесь инструкция stosd сама сдвигает указатель в EDI, а loop привязана к счётчику в ЕСХ, и на каждой итерации авто-уменьшает его на 1. Цикл будет продолжаться, пока ECX не станет нуль:
include 'win32ax.inc'
.data
buff rd 20 ;// приёмный буфер в 20 двойных слов
.code
start:
;// Генерим рандомы и сбрасываем их в буфер
mov edi,buff ;// EDI = адрес приёмника для STOSD
mov ecx,20 ;// ECX = счётчик цикла + маска сдвига рандома
@rnd: rdtsc ;// EAX = тики счётчика TSC
rol eax,cl ;// прокрутим значение-рандом по внешнему счётчику
stosd ;// записать EAX в буфер!
loop @rnd ;// промотать цикл ECX-раз...
;// Создаём файл и записываем в него данные из буфера
invoke _lcreat,<'file.dat',0>,0
push eax
invoke _lwrite,eax,buff,20*4
pop eax
invoke _lclose,eax
;// GAME over!
invoke ExitProcess,0
.end start