回到基础 - 以字符串复制到静态数组
好习惯的方法,strncpy
不是被设计NULL结尾的字符串的工作 - 它不是专为NULL结尾的字符串(如果dest太短它不会被NULL被终止,如果dest更长,它将被零填充)。回到基础 - 以字符串复制到静态数组
所以,这里是一个简单的代码:
const char *src = ....; // NULL terminated string of unknown length
char dest[30];
如何SRC到DEST? strcpy
不安全,strncpy
也是不好的选择。所以我留下了strlen其次是memcpy
? 我想我的解决方案会稍微有所不同目的地不会被截断(目标小于src的长度)或不。
一些限制:
- 遗留代码,所以我不想和不能改变它的std :: string
- 我没有
strlcpy
- GCC不提供它。代码可以用于性能至关重要的应用程序的某些部分(例如,我不想用零填充CPU时间填充dest,因为strncpy
会这样做)。但是,我并不是在谈论过早的优化,而是用C语言来进行字符串复制的愚蠢方式。
编辑
Oopps,我的意思strncpy
而不是snprintf
。我的错误
我刚刚推出自己:
for (int i = 0; i < (sizeof(dest) - 1) && src[i] != NULL; i++)
{
dest[i] = src[i];
}
dest[i] = NULL;
这确保了dest
是空值终止,但从未增加了更多的空值超过必要的。如果您确实对性能敏感,则可以将其声明为宏或共用标头中的内联函数。
如果你不关心截断,您可以使用strncat()
:
dest[0] = 0;
strncat(dest, src, sizeof dest - 1);
随着strncpy:
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
这片用零,但确实要少得多格式的工作比snprintf
。如果你真的必须拥有计算机做尽可能少,自己形容它:
char* last = dest + sizeof(dest) - 1;
char* curr = dest; /* assuming we must not alter 'dest' */
while (curr != last && *src) { *curr++ = *src++; }
*last = '\0'; /* avoids a branch, but always writes.
If branch prediction is working well and the text normally fits:
if (curr == last) { *curr = '\0'; } */
std::copy(src, src+strlen(src)+1, dest)
使用snprintf
。它总是空终止,不会做任何空填充。不知道你对此有何误解...
我想你说的是strncpy()
,它可能不会终止字符串,并会用零填充缓冲区的其余部分。
snprintf()
总是终止目标字符串(只要缓冲区的大小至少为1),并且不用缓冲区填充零。
总之,snprintf()
是你想要什么,除非你非常关心性能。由于snprintf()
需要解释格式字符串(即使它最终所做的是复制字符串),对于有限字符串复制操作,您最好使用strlcpy()
之类的字符串。
(如果你想strlcpy()
,但没有它,你可以得到相当简单。为了完整起见,strlcat()
is here)
我不知道我理解你的问题完全,但如果你”如果你像这样初始化你的数组,它通常可以非常有效地完成零填充。
char dest[30] = { 0 };
如果初始化一样,你不必在意额外的逻辑添加“\ 0”,以字符串的结尾,它甚至可能会更快的转出。
但是,如果您要优化,请记住在优化之前和之后衡量性能。否则始终考虑可读性和可维护性的代码。
把`dest [29] = 0`,使用n = 29的snprintf,不用担心填充。 – sje397 2010-12-06 05:28:44
为什么`snprintf`不好的选择? – MAK 2010-12-06 05:29:01
你只是在你的场所错了。 `snprintf` **总是空终止**和**永不填充**。 – 2010-12-06 06:01:30