加入变量时如何避免sprintf

How to avoid sprintf when joining variables

我正在编写代码以将 USB 设备详细信息放入单个字符串中,并且有以下代码,

    struct usb_bus *bus;
    struct usb_device *dev;

    usb_init();
    usb_find_busses();
    usb_find_devices();

    for (bus = usb_busses; bus; bus = bus->next)
        for (dev = bus->devices; dev; dev = dev->next)
    {

            // working outputs
            printf("Trying device %s/%s\n", bus->dirname, dev->filename);
            printf("Trying device2 %0x\n", dev->descriptor.idVendor);
            printf("Trying device3 %0x\n", dev->descriptor.idProduct);

        char deviceDetailsStr[150]; 
        sprintf(deviceDetailsStr, "%s_%s_%0x_%0x", bus->dirname, 
           dev->filename,dev->descriptor.idVendor,dev->descriptor.idProduct);

        ... have other code here that works on "deviceDetailsStr"
    }

读到 "sprintf" 存在性能问题,因为它支持大量转换。

您能否建议使用 "sprintf" 的更好替代方案,以便将所有 4 个变量数据读入变量 "deviceDetailsStr"

最终目标是 "deviceDetailsStr" 字符数组需要将所有 4 个整数作为单个字符串。

谢谢

第 1 步:确定所需的最大缓冲区大小。

假设 bus->dirname, dev->filename 是数组。

#define Mark_SZ ((sizeof bus->dirname - 1) + 1 + \
    (sizeof dev->filename - 1) + 1 + \
    ((sizeof dev->descriptor.idVendor * CHAR_BIT + 3) /4) + 1 + \
    ((sizeof dev->descriptor.idProduct * CHAR_BIT + 3) /4) + 1)

#defined Extra (depends on: "other code here that works on "deviceDetailsStr"")
char deviceDetailsStr[Mark_SZ + Extra];

第 2 步:复制每个部分

// Some untested code to give you an idea.

char *p = deviceDetailsStr;
size_t n = strlen(bus->dirname); 
memcpy(p, bus->dirname, n);
p += n;

*p++ = '_';

n = strlen(dev->filename); 
memcpy(p, dev->filename, n);
p += n;

*p++ = '_';

p += sprintf(p, "%x", dev->descriptor.idVendor);

*p++ = '_';

sprintf(p, "%x", dev->descriptor.idProduct);

我自己编写了 sprintf(p, "%x", dev->descriptor.idVendor)sprintf(p, "%x", dev->descriptor.idProduct) 代码,希望即使是最普通的编译器也能识别出这一点,并替换为等效的 itoa() 之类的函数调用。否则,只需将 unsigned 替换为 string.

我发现 "0""%0x"

中没有价值

如果你想要最好的性能,我会说你需要写一些自定义的东西。这是您的特定要求的示例。

uint32_t printHex( char * buffer, uint32_t value ) {
    uint32_t sz = value <= 0xF ? 1 :
                  value <= 0xFF ? 2 :
                  value <= 0xFFF ? 3 :
                  value <= 0xFFFF ? 4 :
                  value <= 0xFFFFF ? 5 :
                  value <= 0xFFFFFF ? 6 :
                  value <= 0xFFFFFFF ? 7 : 8;
    for( uint32_t i=sz-1; i; i-- ) {
        buffer[ i ] = ((value & 0xF) <= 9 ? '0' : 'a'-10 ) + (value & 0xF);
        value=value>>4;
    }
    return sz;
}

char buffer[150];
unsigned bi=0;
for( char * ptr = bus->dirname ; *ptr; ptr++ ) buffer[bi++] = *ptr;
buffer[bi++] = '_';
for( char * ptr = bus->filename; *ptr; ptr++ ) buffer[bi++] = *ptr;
buffer[bi++] = '_';
bi += printHex( buffer + bi, dev->descriptor.idVendor );
buffer[bi++] = '_';
bi += printHex( buffer + bi, dev->descriptor.idProduct );
buffer[bi] = '[=10=]';

注意:没有大小检查(就像 sprintf)。同样,如果您想要最佳性能,这是一种权衡。