【问题标题】:C++ custom-written strncpy without padding all characters to null is it safe?C++ 自定义编写的 strncpy 没有将所有字符填充为 null 是否安全?
【发布时间】:2022-01-03 10:10:20
【问题描述】:
#include <iostream>
using namespace std;

struct Packet {
    int a;
    char b[17];
    int c;
};

// char* dest has form char dest[n], src has length <= n and is null-terminated
// After the function, dest should satisfy:
// - If strlen(src)==n, dest is not null terminated
// - If strlen(src) < n, dest[n-1] = dest[strlen(src)] = '\0'
static void strncpy_faster(char* dest, const char* src, size_t n) {
    size_t i;
    for (i = 0; i < n; i++) {
      dest[i] = src[i];
      if (src[i] == '\0')
        break;
    }
    //while (i < n) {dest[i] = '\0'; i++;} // C standard strncpy do this
    if (i < n)
      dest[n - 1] = '\0';
 }
 
 string charArrayToString(const char* a, size_t n) {
    size_t len = 0;
    while (len < n && a[len]!='\0') len++;
    return std::string(a, a+len);
 }

int main()
{
    string s = "12341234123412345";
    Packet packet;
    
    strncpy_faster(packet.b, s.c_str(), 17);
    cout << charArrayToString(packet.b, sizeof(packet.b)) << "\n";
    
    s = "12345";
    strncpy_faster(packet.b, s.c_str(), 17);
    cout << charArrayToString(packet.b, sizeof(packet.b));
    return 0;
}

我正在处理具有固定大小字符数组的结构。假设我真的非常想保持结构的大小很小(或者我需要通过网络发送它们),所以std::string 没有在我的结构中使用(它花费 32 个字节,而我有多个大小为 4- 的小字符数组20)。我对 strncpy 有 2 个问题:

  • strncpy 具有相同长度的 2 个字符数组将发出“可能没有以空字符结尾的字符”的警告,这是有意的,但我不需要该警告。
  • strncpy'\0' 填充所有剩余字符(来自dest[strlen(src) -&gt; n-1])。这在我的程序中浪费了处理。

所以,我的strncpy_faster 最多只能为 '\0' 分配 2 个位置:数组的最后一个元素,以及 strlen(src) 的位置。由于std::string() 需要一个以空字符结尾的字符数组(NTCA),我使用charArrayToString() 将非NTCA 转换为字符串。

这个版本的strncpy 安全吗?是否有任何 C/C++ 函数需要 strncpy'\0' 填充所有剩余字节,或者它们只需要一个空终止符?我不知道为什么标准要求strncpy 将剩余字节清零。

【问题讨论】:

  • 请注意,C/C++ 不是一种语言。 C 和 C++ 是两种不同的语言。您的代码显然是 C++ 而不是 C,所以我删除了 C 标记。
  • 对不起,我一开始并不打算问 std::string。我已经编辑了问题标题
  • @thebusybee yes(我不知道为什么)。
  • 只需要一个空终止符。但是担心将几个字节归零为“浪费处理”是严重不成熟的优化。所有这些库函数都经过高度优化,并且具有几乎肯定会胜过上述 for 循环的快速路径。在你的函数真正被认为是安全的之前,你需要验证很多极端情况。只需使用strncpy - 如果它真的通过网络,您可能希望将您的结构打包。
  • 好吧,如果标准是这样说的,那么您的解决方案并不安全,因为任何用户都可能依赖它。如果您只需要针对特定​​用例的更快版本,您就知道它是否安全。

标签: c++ string c++-standard-library strncpy c-standard-library


【解决方案1】:

这个版本的 strncpy 安全吗?

是的。

它和strncpy 一样安全。所以....不安全。

是否有任何 C/C++ 函数需要 strncpy 用 '\0' 填充所有剩余字节,或者它们只需要一个空终止符?

没有功能需要它。

来自 Linux 手册页 man strcpy 的注释:

注意事项

一些程序员认为 strncpy() 效率低下且出错 易于。如果程序员知道(即包含要测试的代码!) dest的大小大于src的长度,那么strcpy()可以 使用。

strncpy() 的一个有效(和预期)用途是将 C 字符串复制到 一个固定长度的缓冲区,同时确保缓冲区不是 溢出并且目标缓冲区中未使用的字节被清零 出(如果缓冲区是为了防止信息泄漏 写入媒体或通过进程间传输到另一个进程 沟通技巧)。

考虑使用(和/或实施)strlcpy。记住first rule of optimization

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 2016-04-19
    • 2015-03-24
    相关资源
    最近更新 更多