Здравствуйте, прошу помощи у знающих! Начала изучать возможности ассемблеровских вставок в Си. Пересмотрела много материала по этому вопросу, но так и не смогла найти ответ: как можно найти символ с наибольшем кодом ASCII в заранее веденной строке (на СИ) и вывести на экран этот символ с кодом с помощью ассемблера. Заранее спасибо! Код (Text): #include<stdio.h> #include<string.h> #include<conio.h> #include<iostream.h> char *asmfunc(char *S, int n) // функция нахождения символа с //максимальным кодом ASCII в //строке S, n- длина строки { char *r = 0; L0: asm { mov SI,S; // заносим в SI строку S mov DL,n; // заносим в DL длину строки } L1: asm { mov AL,0; // проверка на add AL,[SI]; // конец строки, если конец, то уходим на L3 je L3; } ……. Не знаю что делать для того чтобы организовать поиск символа с наиб кодом L2: asm mov r, ….; // необходимо вывести символ с наибольшим кодом в строке L3: return r; } void main () { char ss[200],sim; char *r; int i, och,n; asm { mov AH, 0; mov AL, 2; int 10H; } printf ("\n vvedite text s tochkoi: \n"); // ввод строки for (i=0; ((sim=getchar()) !='.'); i++) ss[i]=sim; ss[i]='\0'; n=strlen(ss); r=asmfunc(ss,n); //////////////////////povtor programmy cout << "\n\n ochisit akran vvedite 1 ili 0 pov=:"; cin >> och; if (och==1) { asm { mov AH, 0; mov AL, 2; int 10H; } } getch (); }
Прошу прощения, создала не в том разделе. необходимо было в WASM.BEGINNERS. Как перевести в другой раздел?
Alisia Похоже это даже не в BEGINNERS, а в "Студентам с вопросами о лабораторных работах сюда". Если же это искреннее желание научиться то для начала стоит взять компилятор посовременнее - тот древний ДОСовский вряд-ли у кого найдётся в рабочем состоянии, а в более современном - под windows используется другая система комманд ассемблера (32 а не 16 разрядная). Впрочем имхо даже в разделе для лаб ответ маловероятен по той-же причине - без компилятора под рукой код не проверишь, а там ещё и морально устаревшую систему комманд вспоминать надо
Alisia Ошибаешься ) программа написанная на Borland C++ 3.1 работает не на ОС - Windows Xp, а в ДОС эмуляторе встроенном в эту ОС . Поэтому и асм 16разрядный и системные сервисы у тебя ДОСовские, а не виндовые. Была бы задачка на 32 разрядный асм под win, я бы помог, а с ДОС возится неохота и антикварный Borland C++ 3.1 ради этого устанавливать лень.
Размер строки там вроде не требуется. Общий принцип: первый символ приминается за максимум и затем если другой максимум найден до конца строки - перезаписываем код символа и его смещение. Что-то в такой манере: Код (Text): char* FindMaxAsciiCode (char* s) { char chMax; int iMaxOffset; // // Load string address and // assume that first character has // maximum ASCII code for now. // _asm push es _asm les si, s _asm xor cx, cx _asm mov iMaxOffset, cx // iMaxOffset=0 _asm mov al, es:[si] _asm mov chMax, al // // Load characters in loop and // compare them to 'chMax'. // LOAD_NEXT_CHAR: _asm inc si _asm inc cx _asm mov al, es:[si] // // Check if end of string is reached? // _asm test al, al _asm jz END_OF_STRING // // Check if character in AL is larger than 'chMax'? // _asm cmp al, chMax _asm jle LOAD_NEXT_CHAR // // We found a larger character than before. // We need to remember its offset and character value. // _asm mov iMaxOffset, cx _asm mov chMax, al // // Go back for more characters // _asm jmp LOAD_NEXT_CHAR END_OF_STRING: _asm pop si return s + iMaxOffset; } int main () { char* psMax = FindMaxAsciiCode ("dfkJHKHasdhsa:gffd;hdjKJHH63hh-=k"); // // psMax will point to "sdhsa:gffd;hdjKJHH63hh-=k". // return 0; }
Попробывала запустить в Borland C++ - результата не показывает((( Хотя проходит все без ошибок. У меня еще есть Visiol Studio. А там ошибки выдает(( Подскажите, пожалуйста, что я делаю не так.
Alisia Visual Studio какая? 6? 2005? 2008? или тоже древняя под ДОС? Если современная то конечно выдаёт ошибки как раз потому, что там ассемблер другой и не только он.
Alisia И объясни наконец это лаба котрую нужно сделать именно на Borland C++ 3.1 или ты для себя разбираешься и современный компилятор тебе вполне подойдёт?
Да. Это конечно же лаба, но в которой я хочу разобраться))) по заданию стоит Borland C++ 3.1. Но в принципе могу постараться разобраться и в другом компиляторе. visual studio 2008.
Да. Действительно, это от радости, теперь работает))) но результат не правильный(( Выводится только первый символ, а необходимо чтобы выводился символ с наибольшим кодом.
Функция char* FindMaxAsciiCode(char* s), по логике, должна возвращать указатель на требуемый (с макс. кодом) символ в строке, а уж что она действительно возращает разбирайтесь. Вы же хотели разобраться. Обратите внимание на команду проверки, подумайте, почему всегда первый символ выводится...
Alisia Код (Text): __declspec(naked) char __fastcall FindMaxChar(char const *p, int n) { // ecx = p, edx = n __asm { push ebx xor eax, eax // в eax у нас будет результат, а пока что eax = 0 // начнём с конца строки символов (edx используем как индекс текущего символа) jmp prevChar // но на данный момент edx указывает на "послепоследний" символ в строке, // поэтому сразу переходим к предыдущему символу handleChar: movzx ebx, BYTE PTR [ecx+edx] // загружаем текущий символ в ebx cmp eax, ebx // сравниваем его с претендентом на результат cmovb eax, ebx // если он оказался больше, то сам становится претендентом: // eax = ebx если eax < ebx (cmov проверяет флаги, выставленные предыдущим cmp) prevChar: dec edx // переходим к предыдущему символу (уменьшаем индекс): edx = edx - 1. jge handleChar // Если edx >= 0 (мы не вывалились за начало строки) переходим к обработке символа pop ebx ret // возвращаем результат } }
Alisia Вот полный рабочий вариант для msvc 2008. Два варианта поиска на асме (второй более "продвинутый" закомментирован). И два варианта вывода результата на экран (через стандартную CRT библиотеку и через системные функции win api) Для но если для выбора максимального символа в строке асм вставка годится (как учебная задача) то вызов функций вывода на экран из ассемблерной вставки в С программе извращение то ещё. Это безобразие очень сильно зависит от реализации компилятора и даже от его настройки (при статической и динамической линковке CRT способ вызова её функций из асм вставки отличается). Результат выводится на экран 4 раза - два раза из асм вставок и два раза средствами С. ЗЫ: Перенести это 1:1 в Борлад 3.1 не получится, т.к. там и асм другой и вызов системных сервисов тоже. Код (Text): #include <stdio.h> #include <conio.h> #include <tchar.h> #include <windows.h> int _tmain(int argc, _TCHAR* argv[]) { HANDLE hStdout, hStdin; // Handle консоли для вывода на экран // Строковые константы: LPCSTR lpszPrompt1 = "\nInput testing string with point and press Enter\n"; LPCSTR lpszMaxChar = "\nChar with max code \"%c\" (hex code 0x%X)\n"; DWORD cWritten, sizeString; char szString[1024]; // буфер под строку char szTmpStr[1024]; // буфер под временную строку char currentChar, maxChar; // Определить Handle консоли для вывода на экран hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); // Приглашение ввести текстовую строку с точкой (завершение строки Enter) WriteFile(hStdout, lpszPrompt1, strlen(lpszPrompt1), &cWritten, 0); // ввод строки средствами С szString[0] = 0; sizeString = 0; do { currentChar = _getch(); szString[sizeString] = currentChar; // самодельное эхо лучше чем _getche (понимает русские буквы) WriteFile(hStdout, &szString[sizeString], 1, &cWritten, 0); sizeString++; } while (currentChar != 13); // завершить ввод строки по Enter WriteFile(hStdout, "\n", 1, &cWritten, 0); // перевод строки на консоли __asm { // Поиск символа с максимальным кодом вариант 1: // ( с условным переходом ) lea esi, szString // адрес тестируемой строки mov ecx, sizeString // размер тестируемой строки sub ecx, 1 // проверка на пустую строку jbe emptyString xor eax, eax // обнулить сравниваемый символ loop_1: cmp al, [esi + ecx] jnb skip_1 mov al, [esi + ecx] skip_1: sub ecx, 1 jnb loop_1 mov maxChar, al // Поиск символа с максимальным кодом вариант 2: // ( безбранчевый ) /* lea esi, szString // адрес тестируемой строки mov ecx, sizeString // размер тестируемой строки sub ecx, 1 // проверка на пустую строку jb emptyString xor eax, eax // обнулить сравниваемый символ loop_2: cmp al, [esi + ecx] cmovb eax, [esi + ecx] // условное присвоение and eax, 0xFF // маска байта после условного присвоения sub ecx, 1 jnz loop_2 mov maxChar, al */ // ========================================== // Вывод результата средствами библиотеки CRT movzx eax, maxChar push eax // код символа push eax // сам символ push lpszMaxChar // строка с комментариями вывода // Вариант для динамической линковки CRT (ключ /MD) lea eax, printf // вывод на консоль с помощью CRT call [eax] // Вариант для статической линковки CRT (ключ /MT) // call printf add esp, 3*4 // очистка стека после функции в С стиле // ========================================== // Вывод результата средствами ОС (Win API) // (предварительный вывод во временную строку) movzx eax, maxChar push eax // код символа push eax // сам символ push lpszMaxChar // строка с комментариями вывода lea eax, szTmpStr // временная строка push eax lea eax, wsprintfA // вывод во временную строку call [eax] add esp, 4*4 // очистка стека после функции в С стиле // (вывод временной строки на консоль) push 0 lea ecx, cWritten // служебная переменная push ecx push eax // размер временной строки (в eax после функции wsprintf) lea ecx, szTmpStr // временная строка push ecx push hStdout // Handle консоли lea eax, WriteFile // вывод на консоль call [eax] } // Конец ассемблерной вставки // ========================================== // Вывод результата средствами CRT из С printf(lpszMaxChar, maxChar, maxChar & 0xFF); // Вывод результата средствами ОС из С int tmpSize = wsprintfA(szTmpStr, lpszMaxChar, maxChar, maxChar & 0xFF); WriteFile(hStdout, szTmpStr, tmpSize, &cWritten, 0); _getch(); return 0; // Сообщение о пустой строке emptyString: printf("The string is empty/n"); _getch(); return 0; }
Alisia А проблема - в модели компиляции. Есть разные модели компиляции в 16-ти битном С: TINY, SMALL, LARGE, MEDIUM, HUGE, COMPACT. У меня установлена только LARGE на моей версии TC++ 3.1. Проблема возникает потому что адрес имеет разный размер. Например, в LARGE модели - адрес включает сегмент и смещение (поэтому: "LES SI, ..."), а в TINY, к примеру - только смещение, так как сегмент всегда тот же. Попробуй строить код (который я прислал) в модели LARGE и всё заработает. В моделях, где сегмент тот же, надо загружать адрес в регистр SI по другому.