【问题标题】:C, sprintf and "sum" of string and intC、sprintf和string和int的“sum”
【发布时间】:2010-07-08 09:58:57
【问题描述】:

很久没用C了,现在要修改一点代码。有一件事我无法理解:

char filename[20];
filename[0] = '\0';
for (j=0; j < SHA_DIGEST_LENGTH; j++){
  sprintf(filename + strlen(filename),"%02x",result[j]);
}

在第一行中声明了一个 20 个字符的字符串。 在第二行中,第一个字符设置为 '\0',我想也是一个空字符串。

在 for 循环中,我不明白文件名与其长度之间的“总和”...... sprintf 的第一个参数应该是一个缓冲区,用于复制右侧的格式化字符串。这笔款项的结果是什么?在我看来,我正在尝试将一个数组和一个整数相加......

我错过了什么?

【问题讨论】:

    标签: c printf


    【解决方案1】:

    这是指针算法。 strlen 返回 NUL 终止符之前的字符数。添加的结果将指向这个终止符。例如。如果当前字符串为“AA”(后跟 NUL),则 strlen 为 2。filename + 2 指向 NUL。它将在 NUL 和下一个字符上写入下一个十六进制字符(例如 BB)。然后它将再次 NUL 终止它(filename + 4)。那么你就会有“AABB”(然后是 NUL)。

    虽然这并没有真正的意义。寻找那些 NUL 会浪费很多时间。具体来说,它是一种二次算法。第一次,它检查 1 个字符,然后检查 3, 5, 7, ..., 2 * SHA_DIGEST_LENGTH - 1) 。可能只是:

    sprintf(filename + 2 * j,"%02x",result[j]);
    

    还有一个问题。 SHA-1 和的十六进制表示需要 40 个字符,因为一个字节需要两个字符。然后,你有一个最终的 NUL 终止符,所以应该有 41 个。否则,会出现缓冲区溢出。

    【讨论】:

    • @zebediah,你是什么意思? sprintf 将始终添加 NUL 终止符。
    • It will write the next hex character (e.g. C) over this NUL, then NUL-termiante it again sprintf 默认添加\0 吗?
    • 糟糕...yes, it does
    • +1 用于指出效率低下的算法和数组长度错误。并解释指针算法:)
    • 因为我的名声,我不能给 +1 (好像我不是一个好人!)但这是一个非常好的答案!
    【解决方案2】:

    你为什么不声明

    char filename[SHA_DIGEST_LEN*2 +1]; /* 如果你想让 NULL 终止字符,则 +1*/

    这是因为 SHA1 摘要长度为 20 字节,如果您只是打印摘要,那么您可能不需要额外的内存,但由于您想要摘要的十六进制字符串,您可以使用上述声明。 strlen 操作返回字符串的长度,直到遇到空终止字符。

    所以基本上当您执行以下操作时:

    sprintf(filename + strlen(filename),"%02x",result[j]);
    

    在第一次交互中 filname 被复制 2 个字节的 sha-1 摘要第一个字节的十六进制表示。例如。假设是 AA,现在您需要将指针移动两个位置以复制下一个字节。

    在第二次迭代后,它变成了 AABB。 在第 20 次迭代之后,您将拥有整个字符串 AABBCC......AA[40 bytes] 和 +1,如果您需要 '\0' 这是 NULL 终止字符。

    【讨论】:

      【解决方案3】:

      第一次迭代,当 j = 0 时,您将在 filename 的开头写入 3 个字符(是的,包括终止字符串的 '\0'),因为 strlen() 然后返回 0。 下一轮,strlen()返回2,在前两个字符后继续写。

      小心超出分配的 20 个字符空间。常见的错误是忘记了字符串终止符所需的空间。

      编辑:确保 SHA_DIGEST_LENGTH 不大于 9。

      【讨论】:

        【解决方案4】:

        您添加 strlen(filename) 只是为了连接结果[j]

        每次迭代都会在文件名末尾连接当前结果[j],因此每次您需要知道在文件名中偏移应该发生连接的位置。

        【讨论】:

          【解决方案5】:

          将代码替换为:

          char filename[SHA_DIGEST_LENGTH*2+1];
          for (j=0; j < SHA_DIGEST_LENGTH; j++){
            sprintf(filename + 2*j,"%02x",result[j]);
          }
          

          更快、更简单,并且没有错误。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-08-22
            • 1970-01-01
            • 2018-05-17
            • 2019-01-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多