简体   繁体   English

从std :: string复制到char数组并以null结尾结果

[英]copying from a std::string to a char array and null-terminating the result

I have a Visual Studio 2008 C++03 application where I want to copy from a std::string to a char array, but I need the char array to be null terminated even if it must truncate the string to do so. 我有一个Visual Studio 2008 C ++ 03应用程序,我想从std :: string复制到char数组,但我需要将char数组空终止,即使它必须截断字符串才能这样做。

This, for instance works as desired: 例如,这可以按预期工作:

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    source.copy( dest, dest_size );
    using std::min;
    char* end = dest + min( dest_size - 1, source.size() );
    *end = '\0';
}

int main()
{
    enum{ MAX_STRING_SIZE = 15 };
    char dest[ MAX_STRING_SIZE ];
    std::string test = "This is a test";

    CopyAndNullTerminate( test, dest, MAX_STRING_SIZE );

    assert( strcmp( test.c_str(), dest ) == 0 );
    return 0;
}

example: http://ideone.com/0EBYb 例如: http//ideone.com/0EBYb

Is there a shorter, more efficient method of doing this? 是否有更短,更有效的方法?

Thanks 谢谢

Yes, use strncpy , defined in cstring : 是的,使用在cstring定义的strncpy

void copyString(const std::string& input, char *dst, size_t dst_size)
{
    strncpy(dst, input.c_str(), dst_size - 1);
    dst[dst_size - 1] = '\0';
}

Note that for some implementations of std::string (as pointed out by @K-ballo), this may be shorter, but less efficient. 请注意,对于std::string某些实现(如@ K-ballo所指出的),这可能更短,但效率更低。 This is due to the fact that std::string is NOT guaranteed to be implemented using C-syle strings, although for most situations that is probably the case. 这是因为std::string不能保证使用C-syle字符串实现,尽管对于大多数情况可能就是这种情况。

Assuming that dest_size is guaranteed to be at least 1 (which seems reasonable to me, since otherwise it is not possible to copy and null terminate anything into the buffer): 假设dest_size保证至少为1(这对我来说似乎是合理的,否则无法复制并将null终止到缓冲区中):

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    dest[source.copy(dest, dest_size-1)] = 0;
}

In C++11, and in all actively-maintained C++03 implementations (including Visual Studio), std::string has contiguous storage, just like std::vector . 在C ++ 11和所有主动维护的C ++ 03实现(包括Visual Studio)中, std::string具有连续存储,就像std::vector Thus, you could use memcpy instead of std::string::copy and compare performance. 因此,您可以使用memcpy而不是std::string::copy并比较性能。

Likewise you can compare strncpy , std::copy , std::copy_n , strcpy_s , and possibly others I've forgotten, see which is best optimized. 同样,你可以比较strncpystd::copystd::copy_nstrcpy_s ,以及我可能忘记的其他人,看看哪个是最优化的。 In each case, you can compute the number of bytes to copy as std::min(source.size(), dest_size-1) . 在每种情况下,您都可以计算要复制的字节数为std::min(source.size(), dest_size-1) That also avoids the most inefficient case of strncpy (copying a small string into a large buffer). 这也避免了strncpy情况(将一个小字符串复制到一个大缓冲区)。

When doing all these, you can rely on the fact that it is valid to call source[0] even if source is an empty string. 当完成所有这些,你可以依靠的事实,它有效的调用source[0]即使source是一个空字符串。

If you initialize your destination string (to null) first, then you can get it will be null terminated if you don't overwrite the last element in your array. 如果首先初始化目标字符串(为null),那么如果不覆盖数组中的最后一个元素,则可以使其终止。

enum{ MAX_STRING_SIZE = 15 };

char dest[ MAX_STRING_SIZE ] = {0}; // all elements are initialized to 0
std::string test = "This is a test";

// determine the length to copy, it will be the min of MAX_STRING_SIZE-1 
// or test.size.  This will ensure that even if the string it shorter than
// the MAX_STRING_SIZE, that it will copy properly -- without reading past the
// array bounds of the string.
auto copy_len = std::min(test.size(), MAX_STRING_SIZE - 1);

std::copy(
   test.begin(),
   test.begin() + copy_len,
   dest);

This will copy at most 14 characters to your dest object. 这将最多 14个字符复制到您的dest对象。 If the test string is shorter than 14 characters, it will only copy the length of the test string. 如果测试字符串短于14个字符,则只复制测试字符串的长度。 All elements not copied will remain at their initialized value (null). 未复制的所有元素将保持其初始值(null)。

Here are a couple that are shorter: 这是一对较短的一对:

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    *dest = '\0'; // assumes `dest_size > 0`
    strncat(dest, source, dest_size);
}

void CopyAndNullTerminate(std::string const &source,
                          char *dest,
                          size_t dest_size) { 
    sprintf(dest, "%*s", dest_size, source.c_str());
}

Efficient may be open to more question, but I don't see any reason to believe either will be particularly slow. 效率可能会有更多的问题,但我认为没有任何理由相信要么特别慢。

How about the good ole' C strcpy_s? 好的'C strcpy_s怎么样?

strcpy_s(dest, MAX_STRING_SIZE, test.c_str());

I prefer this to strncpy . 我更喜欢这个strncpy The strcpy_s (and it's older cousin strlcpy ) copy loop will terminate after copying the '\\0', but strncpy will always write out the number of bytes specified (padding with '\\0' if the source string is shorter). strcpy_s (及其较旧的表兄strlcpy )复制循环将在复制'\\ 0'后终止,但strncpy将始终写出指定的字节数(如果源字符串较短,则使用'\\ 0'填充)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM