Эффективно преобразуйте между Шестнадцатеричным числом, Двоичным файлом и Десятичным числом в C/C++

Если ваши данные структурированы, и вам нужно получать их разными способами (по порядку или с помощью фильтрации), рекомендуется использовать базу данных SQLite в памяти.

Имейте в виду, что база данных Room также создается как одиночная, поскольку доступ к базе данных должен быть «управляемым» в многопоточных ситуациях.

Не забудьте создать его в методе onCreate вашего класса Application.

9
задан Igor Oks 4 May 2009 в 09:54
поделиться

7 ответов

Как уже отмечали другие, я бы начал с sscanf () , printf () и / или strtoul () . Они достаточно быстры для большинства приложений и с меньшей вероятностью имеют ошибки. Однако я скажу, что эти функции являются более общими, чем вы могли бы ожидать, так как они имеют дело с наборами символов, не относящимися к ASCII, с числами, представленными в любой базе, и так далее. Для некоторых доменов можно превзойти библиотечные функции.

Итак, сначала измерьте, и если производительность этих преобразований действительно является проблемой, то:

1) В некоторых приложениях / доменах определенные числа появляются очень часто, например, ноль, 100, 200, 19,95, может быть настолько распространенным, что имеет смысл оптимизировать ваши функции для преобразования таких чисел с помощью набора операторов if (), а затем вернуться к общим функциям библиотеки. 2) Используйте поиск по таблице, если наиболее распространены 100 чисел, а затем воспользуйтесь библиотечной функцией. Помните, что большие таблицы могут не помещаться в вашем кэше и могут потребовать нескольких косвенных указаний для разделяемых библиотек, поэтому тщательно измеряйте эти вещи, чтобы убедиться, что вы не снижаете производительность.

Возможно, вы также захотите взглянуть на функции boost lexical_cast, хотя в моем последние сравнительно сравнимы со старыми добрыми функциями C.

Несмотря на то, что многие говорили это, стоит повторяться снова и снова: не оптимизируйте эти преобразования, пока не получите доказательства того, что они представляют собой проблему. Если вы оптимизируете, измерьте вашу новую реализацию, чтобы убедиться, что она быстрее , а убедитесь, что у вас есть тонна модульных тестов для вашей собственной версии, потому что вы будете вводить ошибки: - (

8
ответ дан 4 December 2019 в 11:08
поделиться

I would suggest just using sprintf and sscanf.

Also, if you're interested in how it's implemented you can take a look at the source code for glibc, the GNU C Library.

4
ответ дан 4 December 2019 в 11:08
поделиться

That depends on what you're optimizing for, what do you mean by "efficient"? Is it important that the conversions be fast, use little memory, little programmer time, fewer WTFs from other programmers reading the code, or what?

For readability and ease of implementation, you should at least implement both Dec2Hex() and Dec2Binary() by just calling strotul(). That makes them into one-liners, which is very efficient for at least some of the above interpretations of the word.

2
ответ дан 4 December 2019 в 11:08
поделиться

Sounds very much like a homework problem, but what the heck...

The short answer is for converting from long int to your strings use two lookup tables. Each table should have 256 entries. One maps a byte to a hex string: 0 -> "00", 1 -> "01", etc. The other maps a byte to a bit string: 0 -> "00000000", 1 -> "00000001".

Then for each byte in your long int you just have to look up the correct string, and concatenate them.

To convert from strings back to long you can simply convert the hex string and the bit string back to a decimal number by multiplying the numeric value of each character by the appropriate power of 16 or 2, and summing up the results.

EDIT: You can also use the same lookup tables for backwards conversion by doing binary search to find the right string. This would take log(256) = 8 comparisons of your strings. Unfortunately I don't have time to do the analysis whether comparing strings would be much faster than multiplying and adding integers.

1
ответ дан 4 December 2019 в 11:08
поделиться

Почему бы просто не использовать макрос, чтобы также принять формат в качестве входных данных. Если вы находитесь по крайней мере в C.

#define TO_STRING( string, format, data) \
sprintf( string, "##format##", data)
// Int
TO_STRING(buf,%d,i);
// Hex ( Two char representation )
TO_STRING(buf,%02x,i);
// Binary
TO_STRING(buf,%b,i);

Или вы можете использовать sprintf напрямую: или у вас может быть несколько макросов.

#define INT_STRING( buf, data) \
sprintf( buf, "%d", data)
#define HEX_STRING( buf, data) \
sprintf( buf, "%x", data)
#define BIN_TO_STRING( buf, data) \
sprintf( buf, "%b", data)

BIN_TO_STRING( loc_buf, my_bin );
0
ответ дан 4 December 2019 в 11:08
поделиться

Почему эти процедуры должны быть такими эффективными по времени? Такое утверждение всегда заставляет меня задуматься. Вы уверены, что очевидные методы преобразования, такие как strtol (), слишком медленные или что вы можете сделать лучше? Системные функции обычно довольно эффективны. Иногда они медленнее поддерживают общность и проверку ошибок, но вам нужно подумать, что делать с ошибками. Если аргумент bin содержит символы, отличные от '0' и '1', что тогда? Прервать? Распространять массивные ошибки?

Почему вы используете «Dec» для представления внутреннего представления? Dec, Hex и Bin должны использоваться для ссылки на строковые представления. Нет ничего десятичного в длинном без знака . Вы имеете дело со строками, показывающими число в десятичном виде? Если бы не ты'

3
ответ дан 4 December 2019 в 11:08
поделиться

Let's think about half of task for a moment - converting from a string-ized base n to unsigned long, where n is a power of 2 (base 2 for binary and base 16 for hex).

If your input is sane, then this work is nothing more than a compare, a subract, a shift and an or per digit. If your input is not sane, well, that's where it gets ugly, doesn't it? Doing the conversion superfast is not hard. Doing it well under all circumstances is the challenge.

So let's assume that your input is sane, then the heart of your conversion is this:

unsigned long PowerOfTwoFromString(char *input, int shift)
{
    unsigned long val = 0;
    char upperLimit = 'a' + (1 << shift)
    while (*input) {
        char c = tolower(*input++);
        unsigned long digit = (c > 'a' && c < upperLimit) ? c - 'a' + 10 : c - '0';
        val = (val << shift) | digit;
    }
    return val;
 }

 #define UlongFromBinaryString(str) PowerOfTwoFromString(str, 1)
 #define UlongFromHexString(str) PowerOfTwoFromString(str, 4)

See how easy that is? And it will fail on non-sane inputs. Most of your work is going to go into making your input sane, not performance.

Now, this code takes advantage of power of two shifting. It's easy to extend to base 4, base 8, base 32, etc. It won't work on non-power of two bases. For those, your math has to change. You get

val = (val * base) + digit

which is conceptually the same for this set of operations. The multiplication by the base is going to be equivalent to the shift. So I'd be as likely to use a fully general routine instead. And sanitize the code while sanitizing the inputs. And at that point, strtoul is probably your best bet. Here's a link to a version of strtoul. Nearly all the work is handling edge conditions - that should clue you in on where you energies should be focused: correct, resilient code. The savings for using bit shifts is going to be minimal compared to the savings of say, not crashing on bad input.

1
ответ дан 4 December 2019 в 11:08
поделиться