2011-05-09 147 views
19

std::strlen不处理不是\ 0终止的c字符串。它有一个安全版本吗?有没有strlen的安全版本?

PS我知道在C++中应该使用std :: string来代替c字符串,但在这种情况下,我的字符串存储在共享内存中。

编辑

好吧,我需要补充一些解释。

我的应用程序从共享内存(这是一些长度)获取字符串,因此它可以表示为一个字符数组。如果库中存在编写该字符串的错误,则该字符串不会被零终止,并且strlen可能会失败。

+15

...那么什么_does_终止字符串?如果没有字符串终止符,并且没有其他方式从字符串本身推断字符串的长度,则需要将该长度存储在某个单独的变量中。 – 2011-05-09 10:14:04

+9

如果你不知道长度,并且你无法知道长度,那么你无法确定长度。 – 2011-05-09 10:17:11

+3

一段字符串有多长?两次从一端到中间的距离。 – Johnsyweb 2011-05-09 10:20:55

回答

5

如果定义了C-字符串作为

char* cowSays = "moo"; 

那么你autmagically得到 '\ 0' 末和strlen将返回3.如果你将它定义成:

char iDoThis[1024] = {0}; 

你得到一个空的缓冲区(和一组字符,所有这些都是空字符)。只要不超过缓冲区长度,您就可以用自己喜欢的方式填充它。在开始strlen将返回0,一旦你写了东西,你也会从strlen得到正确的数字。
你也可以这样做:

char uhoh[100]; 
int len = strlen(uhoh); 

但这是不好的,因为你不知道那是什么阵列英寸它可能会碰到一个你可能没有的空字符。重点在于空字符是定义的标准方式来声明字符串已完成。
没有空字符表示根据定义字符串未完成。改变这将打破字符串如何工作的范例。你想要做的是制定你自己的规则。 C++会让你做到这一点,但你必须自己写很多代码。

编辑 从你新添加的信息,你想要做的是循环阵列上,检查手空字符。如果您仅希望使用ASCII字符(尤其是在期待字母数字字符的情况下),您还应该进行一些验证。这假定你知道最大尺寸。 如果您不需要验证字符串的内容,那么你可以使用strnlen家庭的功能之一: http://msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm

+4

谢谢。我正在寻找strnlen – 2011-05-09 10:44:10

+6

@VJo:因为'strnlen'不是标准的C或C++,所以你可能更喜欢'memchr'(检查null和指针减法)。或者你可能不介意'strnlen'在Windows和Posix中。 – 2011-05-09 11:27:00

+1

@Steve我不知道它不是标准的,但是因为它是posix,所以对我来说(我正在使用linux)已经足够了。我想这对于在Windows上编程的人来说也已经足够了,因为它在那里 – 2011-05-09 11:38:40

11

非空终止的C字符串不是C字符串,它们只是字符数组,并且无法找到它们的长度。

+2

好的,但是有没有替代std :: strlen这是安全的? – 2011-05-09 10:31:06

+3

@VJo“你没有办法找到他们的长度”你不明白吗? – 2011-05-09 10:33:06

+7

@unapersson:假设用户在“安全”字符串函数(如“strlcpy”)所使用的单词“安全”的非正统含义中表示“安全”,那么您所说的不是真实的。那么,这是真的,但并不相关,因为提问者并没有要求如何找到没有nul终结符的东西的“长度”,他问如何找到长度,如果它有一个,而不是如果它没有崩溃。有人可能知道缓冲区的长度,但不知道它是否包含一个nul字节,它*可以找出哪个长度(如果是字符串)。 – 2011-05-09 11:21:23

0

您需要将您的编码字符串。例如:

struct string 
{ 
    size_t len; 
    char *data; 
} __attribute__(packed); 

然后可以接受的任何字符的数组,如果你知道所述第一的sizeof(为size_t)的共享存储器位置的字节是字符数组的大小。当你想以这种方式链接数组时,它会变得棘手。

最好是相信你的另一端来终止它的字符串,或者推出你自己的strlen,它不会超出共享内存段的行列(提供你至少知道该段的大小)。

3

获得一个更好的图书馆,或者验证你拥有的图书馆 - 如果你不能相信你的图书馆做它说的话,那么你希望你的程序如何?

那是说,假设你知道该字符串所在的buiffer,那

buffer[-1+sizeof(buffer)]=0 ; 
x = strlen(buffer) ; 
  • 使缓冲区比需要更大的长度,然后你可以测试库。

    assert(x<-1+sizeof(buffer)); 
    
+3

那么,写这个库的人不在这里了,而且很sl。。我发现了一个导致strlen失败的bug。无论如何,strnlen正在做我需要的东西 – 2011-05-10 06:38:32

14

您已经添加,字符串是共享内存。这保证了可读性和固定大小。因此,您可以使用size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize)(请注意strnlen中的额外n)。

如果在input之后的共享内存中没有\0,或者如果存在字符串长度,则将返回MaxPossibleSize。 (最大可能字符串长度当然MaxPossibleSize-1的,如果共享内存的最后一个字节是第一\0

+0

是的,那就是我所做的。感谢您的回答 – 2011-05-10 09:54:10

0

如果你需要得到共享内存的大小,尽量使用

// get memory size 
struct shmid_ds shm_info; 
size_t shm_size; 
int shm_rc; 
if((shm_rc = shmctl(shmid, IPC_STAT, &shm_info)) < 0) 
    exit(101); 
shm_size = shm_info.shm_segsz; 

相反使用strlen的时候可以使用shm_size - 1,如果你确定它是空的。否则,你可以通过data [shm_size - 1] ='\ 0'来终止它。然后使用strlen(data);

6
size_t safe_strlen(const char *str, size_t max_len) 
{ 
    const char * end = (const char *)memchr(str, '\0', max_len); 
    if (end == NULL) 
     return max_len; 
    else 
     return end - str; 
} 
+1

您可以重新命名该功能以符合以下要求:http://linux.about.com/library/cmd/blcmdl3_strnlen.htm – harper 2015-06-15 16:17:26

0

一个简单的解决方案:

buff[BUFF_SIZE -1] = '\0' 

OFC这不会告诉你,如果该字符串最初正是BUFF_SIZE-1长或者它只是没有结束...所以你需要为XTRA逻辑。

0

这个怎么样便携金块:

int safeStrlen(char *buf, int max) 
{ 
    int i; 
    for(i=0;buf[i] && i<max; i++){}; 
    return i; 
} 
0

由于Neil Butterworth在他的回答上面已经说:C-字符串未由\ 0字符终止,不C-字符串!

你唯一的机会就是编写一个不可变的适配器,或者用\ 0终止字符创建C字符串的有效副本。当然,如果输入错误,并没有像定义的C-字符串:

char cstring[3] = {'1','2','3'}; 

确实会导致意外的行为,因为可以有类似[email protected]\0在现在内存。所以例如strlen()的结果现在是6而不是3。

下面的方法显示了如何在任何情况下,创建一个安全的C字符串:

char *createSafeCString(char cStringToCheck[]) { 
    //Cast size_t to integer 
    int size = static_cast<int>(strlen(cStringToCheck)) ; 
    //Initialize new array out of the stack of the method 
    char *pszCString = new char[size + 1]; 
    //Copy data from one char array to the new 
    strncpy(pszCString, cStringToCheck, size); 
    //set last character to the \0 termination character 
    pszCString[size] = '\0'; 
    return pszCString; 
} 

这可确保在您操作C-字符串不上别的东西写入内存。

但这不是你想要的。我知道,但没有其他方式来实现字符数组的长度没有终止。这甚至不是一种方法。它只是确保即使用户(或开发人员)插入*****工作正常。