是否有安全版的strlen?

时间:2011-05-09 10:11:28

标签: c++ c string

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

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

修改

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

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

12 个答案:

答案 0 :(得分:15)

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

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

答案 1 :(得分:12)

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

答案 2 :(得分:8)

如果将c-string定义为

char* cowSays = "moo";

然后你自动地在结尾处获得'\ 0'并且strlen将返回3.如果你定义它:

char iDoThis[1024] = {0};

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

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

但那会很糟糕,因为你不知道那个数组中有什么。它可能会击中你可能没有的空字符。关键是null字符是定义的标准方式,用于声明字符串已完成。
没有空字符意味着按照定义字符串未完成。改变这将打破字符串如何工作的范例。你想要做的是制定自己的规则。 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

答案 3 :(得分: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;
}

答案 4 :(得分:3)

获得一个更好的图书馆,或验证你所拥有的图书馆 - 如果你不相信图书馆按照它所说的那样去做,那么你期望你的计划如何?%h& l?

多数民众赞成说,假设你知道字符串所在的buiffer的长度,那么

buffer[-1+sizeof(buffer)]=0 ;
 x = strlen(buffer) ; 
  • 使缓冲区大于需要的值,然后您可以测试lib。

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

答案 5 :(得分:3)

是的,因为C11:

size_t strnlen_s( const char *str, size_t strsz );

位于<string.h>

答案 6 :(得分:0)

您需要对字符串进行编码。例如:

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

如果您知道共享内存位置的第一个sizeof(size_t)字节是char数组的大小,则可以接受任何字符数组。当你想以这种方式链接数组时,它会变得棘手。

最好相信你的另一端终止它的字符串或滚动你自己的strlen,它不会超出共享内存段的bounderies(让你至少知道该段的大小)。

答案 7 :(得分: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;

如果你确定它是空终止的,你可以使用shm_size - 1而不是使用strlen。否则你可以通过数据[shm_size - 1] ='\ 0'将其终止;然后使用strlen(数据);

答案 8 :(得分:0)

一个简单的解决方案:

buff[BUFF_SIZE -1] = '\0'

ofc这不会告诉你字符串最初是完全BUFF_SIZE-1还是刚刚终止...所以你需要xtra逻辑。

答案 9 :(得分:0)

这个便携式金块怎么样:

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

答案 10 :(得分:0)

正如Neil Butterworth在上面的回答中已经说过的那样:未被\ 0字符终止的C-Strings不是C-Strings!

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

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

确实会导致意外行为,因为现在内存中可能会出现类似123@4x\0的内容。因此strlen()的结果现在是6而不是预期的3。

以下方法显示了如何在任何情况下创建安全的C-String:

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-String而不写入别的内存。

但这不是你想要的。我知道,但是没有其他方法可以在没有终止的情况下实现char数组的长度。这甚至不是一种方法。它只是确保即使用户(或开发者)正在插入*****才能正常工作。

答案 11 :(得分:0)

C11包含诸如strnlen_s之类的“安全”功能。 strnlen_s采用额外的最大长度参数(size_t)。如果检查了许多字符后未找到空字符,则返回此参数。如果提供了空指针,它也会返回第二个参数。

size_t strnlen_s(const char *, size_t);

在C11的一部分中,建议您通过编译器的__STDC_LIB_EXT1__定义来检查编译器是否支持这些边界检查“安全”功能。此外,如果用户打算使用这样的功能,则还必须在包含__STDC_WANT_LIB_EXT1__之前将另一个宏1设置为string.h。有关这些函数的起源的某些堆栈溢出注释,请参见here,有关C ++文档的信息,请参见here

GCC和Clang也支持POSIX函数strnlen,并在string.h中提供。微软也提供了strnlen,也可以在string.h中找到。