Автор вопроса: Neco | Web-сайт:neco.pisem.net | ICQ: 247906854
В общем есть такой формат записи станционного протокола, в котором номера телефонов (и не только) записаны в hex-формате. Т.е. например есть телефон 555-12-34 - и в этом протоколе (если просматривать через hex-editor) я прямо эти цифры и вижу: 07 00 00 00 00 05 55 12 24, где 07 это количество знаков, которые надо отсчитать справа налево, чтобы получить номер телефона.
У меня уже есть способ чтения, но он тупой и я бы хотел попросить совета - как можно наиболее быстро прочитать hex в char?
вот кусок конвертора, которым пользовались в нашей конторке испокон веков, но по-моему и он далёк от совершенства:
for (aa = 0, i = 0; aa < bytes; aa++)
{
tmp = in_buf[aa];
hi = (tmp >> 4) & 0x0F;
lo = tmp & 0x0F;
out_buf[i++] = hex[hi];
out_buf[i++] = hex[lo];
}
где hex - массив: char hex[] = "0123456789ABCDEF";
Почему тупой? Я в своих программах на ассемблере использую именно такой, правда реализован он иначе, побыстрее твоего будет, но сам алгоритм по-моему самый подходящий.
Хочешь быстрее - используй ассемблерную вставку.
Кстати, всё-таки можно сделать не через массив hex, а просто прибавлять 48 после сдвига, т.е. к переменным hi и lo, будет побыстрее.
for (aa = 0, i = 0; aa < bytes; aa++)
{
tmp = in_buf[aa];
hi = (tmp >> 4) & 0x0F;
lo = tmp & 0x0F;
out_buf[i++] = hex[hi];
out_buf[i++] = hex[lo];
}
Что-то я не совсем улвавливаю его смысл.
Что такое tmp >> 4?
Может я плохо соображаю отого, что С плохо знаю. BuGOR-то - сразу понял в чем дело. . На VB ,быстрее м/б понял бы.
Насколько я догадался - out_buf - это массив char. Так зачем два раза ему присваивать значения шестнацатиричного кода?
Тпрррр....
Стоп! Вообще не понял, где у тебя принимаемое значение шестнадцатиричного кода или символ?
aa - у тебя по циклу бегает, а что ты преобразуешь?
>>4 это сдвиг на четыре бита. на vb.net это тоже есть.
присваивается один раз каждому следующему элементу - о чём говорит ++.
в массиве char - по индексам соот-щие aсsii значения.
В общем развил тему и составил массив из уже готовых значений для каждого значения байта:
Dim bldr As New System.Text.StringBuilder(1000)
Dim arr_hex() As Char = "0123456789ABCDEF".ToCharArray
Dim arr_full_hex() As String = {"00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F","10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F","20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F","30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F","40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F","50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F","60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F","70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F","80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F","90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F","A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF","B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF","C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF","0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF","F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"}
Public Function ReadCharsToStr(ByVal cBytes As Integer) As String
Try
Dim c As Integer
bldr.Length = 0
Do While c < cBytes
PrepareBuf()
bldr.Append(arr_full_hex(buf(m_seek)))
c += 1
m_seek += 1
Loop
Return bldr.ToString
Catch ex As Exception
Throw ex
End Try
End Function
получилось довольно резво - 60 метровый файл разбирается менее чем за пять секунд.
У кого-нить есть ещё радикально новые мысли? Тут слишком быстро не бывает.
В общем, написал я функцию, протестировал на файле размером 10 метров, на моём Duron950/256, обрабатываетcz меньше, чем за 100 миллисекунд.
Собственно, если ты пишешь на С/С++, то перекласть эту функцию как ассемблерную вставку труда не составит, если же на .NET, то быстрее, чем ты предложил сделать вряд ли удасться.
;ByteArray - указатель на массив байт, который
;требуется перевести в строку.
;OutBuffer - указатель на выходной строковый буфер
;len - размер ByteArray
b2a proc ByteArray:DWORD, OutBuffer:DWORD, len:DWORD
test len,1 ; Проверка чётности
je @f
inc len ; Длина есть число нечётное.
@@:
shr len,1 ; Делим на два. Результат - кол-во
mov ecx,len ; иттераций нашего цикла.
mov esi,ByteArray
mov edi,OutBuffer
@@:
lodsb ; Грузим первый байт(например 12) в регистр al
shl ax,4 ; Сдвигаем и получаем в ax 0120
shr al,4 ; Сдвигаем ещё раз и получаем 0102
add ax,3030h ; Прибавляем коэффицент, после чего в ax имеем 3132
;или "12" в acsii представлении
ror ax,8 ;Чтобы записать данные в правильном порядке нужно поменять значения младших регистров местами, т.е. имеем 3231
stosb ;Записываем первый байт
shr ax,8 ;Подготавливаем к записи второй
stosb ;Записываем его.
dec ecx
jne @b
ret
b2a endp
vito
А ты доведи до ума его, далее сравним, хотя я даже щас могу сказать, что в конечном варианте он у тебя будет медленнее моего имхо, т.к. тебе минимум за одну иттерацию придётся обратиться 3 раза к памяти(два раза чтение: загрузка байта, и загрузка табличного значения и одна операция записи, т.е. запись результата), а в данном случае обращения к памяти являются ключевым "тормозом".
Мда...
Дико извиняюсь, но если номер 555-12-34, то в hex это должно быть что-то типа 02 2B 0C 22, а не 05 55 12 24.
Если информация всё-таки записана в виде 05 55 12 24, то это не hex-форма. Скорее нечто из области двоично-десятичных представлений.
Строки для всех номеров имеют вид "07 00 00 00 00 05 55 12 24" ? После 07 обязательно будут незначащие нули? Длина строк - величина постоянная или нет?
Дико извиняюсь, но если номер 555-12-34, то в hex это должно быть что-то типа 02 2B 0C 22, а не 05 55 12 24
Нет вот именно 05 55 12 24. Такова реальность.
Длина строк - величина постоянная или нет?
Постоянная - в примере я не соблюдал, просто понатыкал несколько пар нулей. На самом деле для абонента А отведено 9 байт (2 на кол-во цифр, 16 на номер) для абонента Б - 18 (2 на кол-во, 34 на номер). Ну и там не только такого типа значения, есть и обычные бинарные (только с изменённым порядком байт - в них даются размеры блоков и записей), есть и acsii (фамилии операторов) поэтому надо постоянно смотреть в доку и по ней всё делать.