回到基础 - 以字符串复制到静态数组

问题描述:

好习惯的方法,strncpy不是被设计NULL结尾的字符串的工作 - 它不是专为NULL结尾的字符串(如果dest太短它不会被NULL被终止,如果dest更长,它将被零填充)。回到基础 - 以字符串复制到静态数组

所以,这里是一个简单的代码:

const char *src = ....; // NULL terminated string of unknown length 
char dest[30]; 

如何SRCDESTstrcpy不安全,strncpy也是不好的选择。所以我留下了strlen其次是memcpy? 我想我的解决方案会稍微有所不同目的地不会被截断(目标小于src的长度)或不。

一些限制:

  • 遗留代码,所以我不想和不能改变它的std :: string
  • 我没有strlcpy - GCC不提供它。代码可以用于性能至关重要的应用程序的某些部分(例如,我不想用零填充CPU时间填充dest,因为strncpy会这样做)。但是,我并不是在谈论过早的优化,而是用C语言来进行字符串复制的愚蠢方式。

编辑

Oopps,我的意思strncpy而不是snprintf。我的错误

+1

把`dest [29] = 0`,使用n = 29的snprintf,不用担心填充。 – sje397 2010-12-06 05:28:44

+1

为什么`snprintf`不好的选择? – MAK 2010-12-06 05:29:01

+3

你只是在你的场所错了。 `snprintf` **总是空终止**和**永不填充**。 – 2010-12-06 06:01:30

我刚刚推出自己:

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”,以字符串的结尾,它甚至可能会更快的转出。

但是,如果您要优化,请记住在优化之前和之后衡量性能。否则始终考虑可读性和可维护性的代码。