std::strlen不处理未被\ 0终止的c字符串。它有安全版本吗?
PS我知道在c ++中应该使用std :: string而不是c字符串,但在这种情况下,我的字符串存储在共享内存中。
修改
好的,我需要补充一些解释。
我的应用程序从共享内存(有一定长度)获取一个字符串,因此它可以表示为一个字符数组。如果库中有一个错误写这个字符串,那么该字符串不会被零终止,并且strlen可能会失败。
答案 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)
答案 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
中找到。