【问题标题】:C: split 32 bit unsigned int into bytes and construct string based on resultsC:将 32 位 unsigned int 拆分为字节并根据结果构造字符串
【发布时间】:2014-01-07 00:57:00
【问题描述】:

我正在尝试将 32 位无符号整数拆分为 4 个字节的数组,然后在字符串中重构这些字节以用作文件路径

我正在使用位移将 int 拆分为 char 数组,如下所示:

void splitIntegerUsingBitShifting(int value, unsigned char *result)
{
    result[0] = (value >> 24) & 0xFF;
    result[1] = (value >> 16) & 0xFF;
    result[2] = (value >> 8) & 0xFF;
    result[3] = value & 0xFF;
}

目前只能使用 sprintf 命令成功创建文件路径:

+ (void) storeIntegerStructureUsingBitShifting:(int) fingerprint trackID:(int) track
{
    unsigned char bytes[4];
    splitIntegerUsingBitShifting(fingerprint, bytes);

    char home[15] = "/rootdirectory/";
    char fullpath[100];
    char *delimeter = "/";

    sprintf(fullpath, "%s%d%s%d%s%d%s%d", home, bytes[0], delimeter, bytes[1], delimeter, bytes[2], delimeter, bytes[3]);
    printf("\"%s\"", fullpath);

}

我已经读到 sprintf 命令在性能方面可能代价高昂,并且由于我将调用此函数数千次,想知道是否有人建议以更好/更快的方式实现此目的。

提前感谢您的任何建议。

【问题讨论】:

  • 如果您使用这些文件路径打开文件,与打开/创建文件的系统开销相比,sprintf 开销可能微不足道。顺便说一句,我建议使用 %u 而不是 %d 以避免负数。
  • 如果您在其他地方使用 printf 而不仅仅是调试,sprintf 将增加可忽略不计的开销。如果您不介意 HEX 值,则转换为 HEX 字节非常简单,例如const char hexmap="0123456789ABCDEF";字符[0]=hexmap[字节[0]>>4];字符[1]=hexmap[字节[0]&0x0F];等等;;;
  • DoxyLover 和 EkriirKe - 感谢您的建议。我接受了 ikh 的回答,因为它不使用 sprintf 并以十进制格式生成输出

标签: c arrays


【解决方案1】:

您可以使用 strXXX 函数和 itoa 函数来代替 sprintf。例如:

char buf[4];
strcpy(fullpath, home);
itoa(bytes[0], buf, 10);
strcat(fullpath, buf);
strcat(fullpath, delimeter);
itoa(bytes[1], buf, 10);
strcat(fullpath, buf);
strcat(fullpath, delimeter);
itoa(bytes[2], buf, 10);
strcat(fullpath, buf);
strcat(fullpath, delimeter);
itoa(bytes[3], buf, 10);
strcat(fullpath, buf);
strcat(fullpath, delimeter);

如果你还有抱怨,你可以重写itoa只写十进制(也可能需要,因为itoa不是标准C),自己写strcpy/ strcat 返回/接收 fullpath 的长度。 (每个strcat都找fullpath的长度,没必要。)

如果你想要可变字符串的长度,你可以使用std::string。 (我不知道它的性能。。如果你用这个,你可能需要比较性能。)哦,你的代码似乎是Objective-C..

【讨论】:

  • 我在网上找到了一个 itoa 的实现(正如你所建议的,它不能作为标准 C 函数使用),这正是我想要做的,所以我要选择它作为公认的答案。感谢您的帮助
【解决方案2】:

这里有一个建议:将值拆分为半字节(4 位值)并使用每个半字节作为字符串0123456789abcdef 的索引,这将为您提供字符串的十六进制表示。当然,有一个“标准”函数(虽然不是其广泛可用的标准库的一部分):itoa,基数为 16。

【讨论】:

  • 好主意,除了格式字符串表明需要十进制值,而不是十六进制。
  • datenwolf - 感谢您的回复。我接受了 ikh 的回答,因为它以十进制格式生成输出,但为 itoa 的建议欢呼。
【解决方案3】:

你可以在没有库函数的情况下做到这一点,比如滚动你自己的 itoa 版本,限制为单字节输入:

unsigned char bytes[5];
char outstr[16]; // 3 digits *4 bytes + 3 delimiters + terminator
int i,j,n,d;

splitIntegerUsingBitShifting(fingerprint, bytes);
for (i=j=0;i<4;i++){
  for (d=100;d;d/=10){ 
    n=bytes[i]/d;
    bytes[i]%=d;
    if (n||d==1)   //remove this line if you want all dirs to be 3 digit numbers.
      outstr[j++]=n+'0';
   }
   outstr[j++]=delimiter;
 }
 outrstr[--j]='\0'; //overwrite trailing delimiter 

【讨论】:

  • 感谢您的建议,但是当我为指纹运行此程序时,我希望“7/71/234/131”(然后将其附加到 home 中的值
  • 我没有测试就发布了。修复了小错误。
【解决方案4】:

您不需要移位和复制单个字符。 您可以改为将 memcpy 所需的 4 个字节设置为 char str[5]; 数组并将最后一个字节设置为 '\0'

int val = 0xabcd3434;
char str[5];
memcpy(str, &val, sizeof(int)); // hopefully its 4 ;)
str[4] = '\0';

printf("%s", str);

【讨论】:

  • 这会产生很多不可打印的字符和文件名中不允许出现的字符。 -1
  • 您假设文件系统允许非 ASCII 字符,包括 NULL。它在具有不同字节序的 CPU 上不太便携,但如果 OP 将其保留给自己从不改变拱门,则可能无关紧要。最后 OP 不想使用 *printf。
猜你喜欢
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 2012-08-09
相关资源
最近更新 更多