Как реализовать printf-подобную функциональность в ассемблере? - PullRequest
2 голосов
/ 28 марта 2011

Я очень жду отзывов и рекомендаций, а не прямого ответа.

Используя инструкции ассемблера .586, как вы можете имитировать printf-подобные функции? Для полей фиксированной ширины я знаю, что могу сделать что-то вроде этого:

.data
  Format BYTE 'You are ## years old.',0

А затем перед печатью строки просто замените значения ## на соответствующее число, затем измените их обратно на случай, если мне понадобится несколько раз использовать строку формата с разными значениями.

Возможно, это не лучший способ, но пока он работает.

Чего я не могу понять, так это как сделать это, если вы заранее не знаете количество цифр. Опция формата подходит, если вы знаете максимальное количество цифр, которое вы хотите использовать (приведенный выше пример не будет работать так же, как для людей старше 100 лет, вы теряете пробелы между словами).

Если вы зарезервируете слишком много места, вы получите двойные пробелы между вашим числом и вашими мирами.

.data
  Format BYTE 'You are ### years old.',0

Использование моей схемы с кем-то, кому 12, даст:

You are  12 years old.

Моя единственная мысль была о том, что там был персонаж ASCII, который ничего не печатал (кроме \0), но он кажется липким.

Вся проблема возникает потому, что инструктор хочет, чтобы мы могли печатать форматированную строку этого типа, используя один вызов процедуры PrintString (которую он нам предоставил), которая ищет для esi значение \0 завершенный байтовый массив.

Ответы [ 3 ]

1 голос
/ 28 марта 2011

Вы предполагаете, что ваши выходные данные будут в том же буфере, который используется для задания форматирования - процедуры C printf() этого не делают. Также следует понимать, что преобразование, вызванное спецификатором формата, не должно занимать то же количество символов в выводе, что и спецификатор формата. Например, спецификатор printf() %s может занимать более 2 символов в выводе (или может использовать менее 2 символов).

Вы можете сделать так, чтобы ваша процедура сборки выполняла то же самое, что и процедуры C - строка формата вводится в функцию (и не изменяется), как и элементы, которые должны быть преобразованы, как указано в строке формата. Вывод, созданный функцией, идет куда-то еще - либо в процедуру вывода, которая отправляет данные в файл или устройство, либо в буфер памяти, предоставленный вызывающей стороной.

Когда функция просматривает строку формата, она может решить, нужно ли вводить символы в вывод без изменений (т. Е. Символы в строке формата, которые не являются спецификатором формата). Когда дело доходит до спецификатора формата, он использует другой входной параметр, преобразует его в соответствии со спецификатором формата и отправляет эти символы на выход.

1 голос
/ 28 марта 2011

Ну, вы должны быть в состоянии рассчитать количество цифр, которое вам нужно во время выполнения. Тогда у вас есть несколько альтернатив:

  • Выделите максимальное пространство заранее, а затем сдвиньте левые части вашей строки, чтобы не осталось лишних пробелов.

  • Используйте только один пробел, а затем растяните и сдвиньте строку вправо, чтобы добавить больше места по мере необходимости. Я думаю, что у вас есть несколько проблем с управлением памятью, хотя ...

0 голосов
/ 02 июня 2018

Сначала определите escape-последовательности для каждого типа данных, например, «% f», и поместите их в таблицу пар ключ-значение. Затем разбейте задачу на следующие подпрограммы:

  • Процедура indexOf , которая принимает указатель на строковый буфер и начальный индекс. Он ищет одну из escape-последовательностей, которые вы определили из начального индекса, и возвращает ее индекс, если escape-последовательность найдена, или -1, если ни одна не найдена.

  • A функция print для каждого типа данных, одна для целых чисел, целых чисел без знака, чисел с плавающей запятой и т. Д., Которая берет данные по значению и выводит их на экран.

  • Функция printf получает указатель на строковый буфер и данные для вставки и выводит их на экран.

В printf создайте цикл, который ищет escape-последовательность с помощью indexOf. Если найдено, выведите исходную строку до индекса, возвращаемого indexOf. Определите тип данных в таблице, затем распечатайте данные с помощью соответствующей функции печати. Запустите цикл снова, ища по новому индексу после escape-последовательности. Цикл до конца строки источника. Готово. Нет необходимости динамически выделять память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...