我遇到了两种流行的方法来编写一个可移植的安全复制功能,并且符合C89。
示例1:
strncpy(dst, src, size);
dst[size - 1] = '\0';
示例2:
dst[0] = '\0'
strncat(dst, src, size - 1);
我的问题:
答案 0 :(得分:2)
是的,它们在技术上是不同的。虽然你可能不关心微不足道的差异。
e.g。如果你这样初始化:
npm install email-validator --save
然后使用“示例1”,char dst[] = "abcdefg";
char src[] = "12";
size_t size = sizeof dst;
变为dst
使用“示例2”,0x31 0x32 0x00 0x00 0x00 0x00 0x00 0x00
变为dst
如果您只想复制字符串,那么差异无关紧要。
很难说哪一个更好。但是在非常大0x31 0x32 0x00 0x64 0x65 0x66 0x67 0x00
和非常短size
的情况下,使用“示例1”方法设置所有尾随空字符可能会使程序变慢。
答案 1 :(得分:-1)
https://en.cppreference.com/w/cpp/string/byte/strncat
https://en.cppreference.com/w/cpp/string/byte/strncpy
这是一个 C++(哈哈哈)的例子,说明了不同之处:
https://wandbox.org/permlink/igKe0CtdyuMw1JHL
#include <iostream>
#include <cstring>
#include <cassert>
//////////////////////////////////////////////////////////
// using strncat
// https://en.cppreference.com/w/cpp/string/byte/strncat
template <std::size_t N>
inline void safestrcpy1(char *dest, const char *src)
{
constexpr std::size_t count = N-1;
dest[0] = '\0';
strncat(dest, src, count); // at most count characters are copied from string src;
// and then a terminating null character '\0' is written if it was not yet encountered
}
template <std::size_t N>
inline void safestrcpy1(char (&dest)[N], const char *src)
{
safestrcpy1<N>(&dest[0], src);
}
//////////////////////////////////////////////////////////
// using strncpy
// https://en.cppreference.com/w/cpp/string/byte/strncpy
template <std::size_t N>
inline void safestrcpy2(char *dest, const char *src)
{
constexpr std::size_t count = N-1;
strncpy(dest, src, count); // null termination '\0' is only written if it occurs somewhere within src[0] .. src[count-1]
// if it occurs at src[i] and i < count, then dest[i+1], dest[i+2], ... dest[count-1] are also set to '\0'.
dest[count] = '\0'; // ensure null termination
}
template <std::size_t N>
inline void safestrcpy2(char (&dest)[N], const char *src)
{
safestrcpy2<N>(&dest[0], src);
}
//////////////////////////////////////////////////////////
// main
//
int main()
{
{
char dest1[4] = "xyz";
char dest2[4] = "xyz";
safestrcpy1(dest1, "");
safestrcpy2(dest2, "");
#define RES1A "\0yz"
#define RES2A "\0\0\0"
assert(memcmp(dest1, RES1A, sizeof(RES1A)) == 0);
assert(memcmp(dest2, RES2A, sizeof(RES2A)) == 0);
std::cout << dest1 << std::endl;
}
{
char dest1[4] = "xyz";
char dest2[4] = "xyz";
safestrcpy1(dest1, "1");
safestrcpy2(dest2, "1");
#define RES1B "1\0z"
#define RES2B "1\0\0"
assert(memcmp(dest1, RES1B, sizeof(RES1B)) == 0);
assert(memcmp(dest2, RES2B, sizeof(RES2B)) == 0);
std::cout << dest1 << std::endl;
}
{
char dest1[4] = "xyz";
char dest2[4] = "xyz";
safestrcpy1(dest1, "12");
safestrcpy2(dest2, "12");
#define RES1C "12\0"
#define RES2C "12\0"
assert(memcmp(dest1, RES1C, sizeof(RES1C)) == 0);
assert(memcmp(dest2, RES2C, sizeof(RES2C)) == 0);
std::cout << dest1 << std::endl;
}
{
char dest1[4] = "xyz";
char dest2[4] = "xyz";
safestrcpy1(dest1, "123");
safestrcpy2(dest2, "123");
#define RES1D "123"
#define RES2D "123"
assert(memcmp(dest1, RES1D, sizeof(RES1D)) == 0);
assert(memcmp(dest2, RES2D, sizeof(RES2D)) == 0);
std::cout << dest1 << std::endl;
}
{
char dest1[4] = "xyz";
char dest2[4] = "xyz";
safestrcpy1(dest1, "1234");
safestrcpy2(dest2, "1234");
#define RES1E "123"
#define RES2E "123"
assert(memcmp(dest1, RES1E, sizeof(RES1E)) == 0);
assert(memcmp(dest2, RES2E, sizeof(RES2E)) == 0);
std::cout << dest1 << std::endl;
}
}