【发布时间】: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) -> 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