【问题标题】:strncpy and using sizeof to copy maximum charactersstrncpy 并使用 sizeof 复制最大字符
【发布时间】:2010-11-13 16:29:27
【问题描述】:

我正在使用下面的代码

char call[64] = {'\0'} /* clean buffer */
strncpy(call, info.called, sizeof(call));

我总是使用 sizeof 作为目标来保护溢出,以防源大于目标。这样我可以防止缓冲区溢出,因为它只会复制目标可以处理的数量。

但我现在想知道它是否会终止目的地。

几个案例。

1) 如果源更大。 我可以这样做:

call[strlen(call) - 1] = '\0'; /* insert a null at the last element.*/

2) 如果源小于目标。 call 是 64 个字节,我复制了 50 个字节,因为这是源的大小。会自动把null放到51元素里面吗?

非常感谢您提供任何信息,

【问题讨论】:

    标签: c strncpy


    【解决方案1】:

    strncpy 如果截断字符串,将以空值终止目标。如果一定要使用strncpy,则需要确保结果被终止,类似:

    strncpy(call, info.called, sizeof(call) - 1);
    call[sizeof(call) - 1] = '\0';
    

    BSD 的strlcpy() 等通常被认为是优越的:

    http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy

    【讨论】:

    • 一种简单的方法来确保目的地在此处被 nul 终止是 call[sizeof call -1] = 0;
    • 我不认为 strncpy 会终止字符串。通过不终止字符串。这会导致真正的问题吗?同样通过调用[strlen(info.call - 1] = '\0'; 如果源大于或小于目标,终止的正确方法是什么?谢谢。
    • 是的,未终止的字符串会导致 strlen()strcat() 等错误、损坏内存和/或崩溃。当字符串比目标字符串短时,将缓冲区的最后一个字节设置为零不会造成任何损害,因此真的没有理由让它成为条件。
    • 如果您使用的是 VC++,我建议您使用 strncpy_s,它可以确保字符串始终被终止
    • strncpy() 的另一个技巧是,当源比目标短时,它总是将目标字符串完全填充为指定的长度。如果将 32 字节的数据复制到 4 KB 的缓冲区中,这很重要;除了 32 字节的数据,它还会复制 4064 个 '\0' 字符——这可能会成为一个问题。在我看来,strncpy() 旨在将最多 14 个字符的文件名组件复制到旧 Unix 目录条目的文件名部分。文件名部分最多 14 个字符,填充空但不以空结尾(前两个字节是 2 字节的 inode 编号)。
    【解决方案2】:

    如果源的长度小于,作为第三个参数 strncpy 传递的最大数量将终止目标,否则 - 不是。

    如果源的长度等于或大于目标的长度 - 处理它是您的问题。像你建议的那样做 - 调用 strlen() - 将不起作用,因为缓冲区不会以空值结尾,你会遇到未定义的行为。

    你可以分配一个更大的缓冲区:

    char buffer[bufferSize + 1];
    strncpy( buffer, source, bufferSize );
    *(buffer + bufferSize ) = 0;
    

    【讨论】:

      【解决方案3】:

      你的想法:

      call[strlen(call) - 1] = '\0';
      

      不起作用,因为您将在非终止字符串上调用 strlen()

      【讨论】:

        【解决方案4】:

        1) 来自cplusplus.com:“没有空字符隐式附加到目标末尾,因此只有在源中 C 字符串的长度小于 num 时,目标才会以空字符结尾。”所以如果你需要你的字符串以空值结尾,你需要这样做:

        call[sizeof(call) - 1] = '\0';
        

        这样做的一个好方法是为strncpy 编写一个包装函数,该函数始终确保字符串被终止。

        2) 如果源比目标短,目标将以空值结尾。

        【讨论】:

          【解决方案5】:

          但我现在想知道它是否会终止目的地。

          不,strncpy 不承诺目标字符串将以空值结尾。

          char tar[2]={0,0};
          char bar="AB";
          strncpy(tar,bar,2);
          // result tar[0]=='A'; tar[1]=='B'
          

          为了使它正确,你应该使用:

          strncpy(traget,string,sizeof(target)-1);
          target[sizeof(target)-1]=0
          

          【讨论】:

          • 我只是想知道。使用 strlen 或 sizeof 有什么真正的区别吗?
          • sizeof 是常量,当 strlen 在运行时实际计算字符串的长度时,它返回 sizeof 对象。例如对于 char tar[2]={0,0}; sizeof(tar)==2 但是,strlen(tar)==0;
          【解决方案6】:

          只需使用 strlcpy() 代替 strncpy()。 您必须检查它是否在所有平台上都可用。 早期版本的 linux 可能没有。

          【讨论】:

          • 这不是标准功能。它可能不可用。
          【解决方案7】:

          strlcpy 的使用方式与 strncpy 相同。第三个参数不需要做size-1

          即: strncpy(call, info.called, sizeof(call)-1); 要么 strlcpy(call, info.called, sizeof(call));

          【讨论】:

          • -1 应该在这里做什么?它只会将问题转移一个字节。如果字符串不适合sizeof(call)-1 字节,则剩余的最后一个元素仍不会用0 填充。 6 年前就有人建议使用strlcpy
          • 这仅在目标缓冲区在调用之前被清除为 0 时才有效。对于一般使用不是很有帮助。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-25
          • 1970-01-01
          • 1970-01-01
          • 2012-05-12
          • 2015-02-04
          相关资源
          最近更新 更多