Я должен генерировать строку пути от числа (в C)
например:
53431453 -> 0003/2F4/C9D
что я имею, до сих пор это:
char *id_to_path(long long int id, char *d)
{
char t[MAX_PATH_LEN];
sprintf(t, "%010llX", id);
memcpy(d, t, 4);
memcpy(d+5, t+4, 3);
memcpy(d+9, t+7, 4);
d[4] = d[8] = '/';
return d;
}
Я задаюсь вопросом, существует ли лучший путь, например, генерировать заключительную строку за один шаг вместо того, чтобы делать sprintf и затем переместить байты.
Спасибо
Править:
Я сравнил данных решений
результаты в операциях в секунду (выше лучше):
(1) sprintf + memcpy : 3383005
(2) single sprintf : 2219253
(3) not using sprintf : 10917996
при компиляции с-O3 различие еще больше:
(1) 4422101
(2) 2207157
(3) 178756551
Так как эта функция будет вызвана много, я буду использовать быстрое решение даже при том, что единственный sprintf является самым коротким и самым читаемым.
Спасибо за Ваши ответы!
Поскольку строка использует шестнадцатеричный формат, это довольно легко сделать с помощью операторов сдвига и битов.
Получить 4 старших бита из значения можно следующим образом:
id >> 28
Преобразование этого в цифру просто означает добавление к нему символа «0», например:
'0' + (id >> 28)
Однако, поскольку A, B, C , ... не следует сразу за символом 9, мы должны выполнить дополнительную проверку, например:
if (c > '9') c = c - '9' - 1 'A'
Если нам нужны следующие 4 бита, мы должны сдвинуть только 24 бита, но тогда у нас все еще есть самые высокие 4 бита. осталось бит, поэтому мы должны замаскировать их, например:
(id >> 24) & 0xf
Если мы добавим это в вашу функцию, мы получим следующее:
char convert (int value)
{
char c = value + '0';
if (c > '9') c = c - '9' - 1 + 'A';
return c;
}
void main()
{
long id = 53431453;
char buffer[20];
buffer[0] = convert(id >> 28);
buffer[1] = convert((id >> 24) & 0xf);
buffer[2] = convert((id >> 20) & 0xf);
buffer[3] = convert((id >> 16) & 0xf);
buffer[4] = convert((id >> 12) & 0xf);
buffer[5] = convert((id >> 8) & 0xf);
buffer[6] = convert((id >> 4) & 0xf);
buffer[7] = convert((id >> 0) & 0xf);
buffer[8] = '\0';
}
Теперь настройте это, чтобы добавить косые черты между ними, дополнительные нули в начале, .. .
РЕДАКТИРОВАТЬ: Я знаю, что это не за один шаг, но это лучше расширяемо, если позже вы захотите поменять места косых черт, ...
Вы уже пробовали этот вариант?
typedef struct {
unsigned f7 : 4;
unsigned f6 : 4;
unsigned f5 : 4;
unsigned f4 : 4;
unsigned f3 : 4;
unsigned f2 : 4;
unsigned f1 : 4;
unsigned f0 : 4;
} lubf;
#define convert(a) ( a > 9 ? a + 'A' - 10 : a + '0' )
int main()
{
lubf bf;
unsigned long a = 0xABCDE123;
memcpy(&bf, &a, sizeof(a));
char arr[9];
arr[0] = convert(bf.f0);
arr[1] = convert(bf.f1);
arr[2] = convert(bf.f2);
arr[3] = convert(bf.f3);
arr[4] = convert(bf.f4);
arr[5] = convert(bf.f5);
arr[6] = convert(bf.f6);
arr[7] = convert(bf.f7);
arr[8] = '\0';
printf("%lX : %s\n", a, arr);
};
Не тестировалось, но вы можете разделить int на три и распечатать его:
char *id_to_path(long long int id, char *d)
{
sprintf(d, "%04llX/%03llX/%03llX", ( id >> 24 ) & 0xffff, ( id >> 12 ) & 0xfff, id & 0xfff);
return d;
}