C 将数字转换为斜线分割的十六进制路径

C 将数字转换为斜线分割的十六进制路径,c,optimization,C,Optimization,我需要从一个数字(在C中)生成一个路径字符串 e、 g: 到目前为止,我得到的是: 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] = '/';

我需要从一个数字(在C中)生成一个路径字符串

e、 g:

到目前为止,我得到的是:

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然后移动字节

谢谢

编辑:

我对给定的解决方案进行了基准测试

每秒操作数的结果(越高越好):

使用-O3编译时,差异更大:

(1) 4422101
(2) 2207157
(3) 178756551
因为这个函数会被多次调用,所以我将使用最快的解决方案,即使单个sprintf是最短、最可读的


谢谢你的回答

未测试,但您可以将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;
}

由于字符串使用十六进制,因此可以很容易地使用移位和位运算符来完成

从值中获取4个最高位的操作如下:

id >> 28
'0' + (id >> 28)
(id >> 24) & 0xf
将其转换为数字只意味着向其添加字符“0”,如下所示:

id >> 28
'0' + (id >> 28)
(id >> 24) & 0xf
然而,由于A,B,C。。。不要立即跟随字符9,我们必须执行额外的检查,例如:

if (c > '9') c = c - '9' - 1 'A'
如果我们想要接下来的4位,我们应该只移动24位,但是我们仍然有最高的4位,所以我们应该屏蔽它们,如下所示:

id >> 28
'0' + (id >> 28)
(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);
};

+1,但这里的每个人似乎都认为
long
始终是32位。人们可能不应该这样做,或者,如果有这样的假设,那么对原型使用
int32t
。或者更好地使用
uint32\u t
,因为
id
的语义似乎是无符号的,只是一个位模式。@Jens您无法从32位数字中获得10个十六进制数字。假设它至少是40位,否则msb中的1将在右移时进行符号扩展。我倾向于使用uint64_t来澄清我自己,但这不是给出的原型。是的,memcpy使它比按位操作慢得多。更好的方法是使用具有位域结构和无符号long的并集,您可以指定long,但可以通过位域结构访问相同的数据。但是,性能仍然比按位操作选项差。此外,我不确定,但我认为该解决方案存在可移植性问题,因为位顺序(endianness),在64位框上,大小为8的框(a)太大,无法复制到lubf。