C++ 有安全版本的strlen吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5935413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a safe version of strlen?
提问by B?ови?
std::strlendoesn't handle c strings that are not \0 terminated. Is there a safe version of it?
std::strlen不处理未 \0 终止的 c 字符串。有安全版本吗?
PS I know that in c++ std::string should be used instead of c strings, but in this case my string is stored in a shared memory.
PS 我知道在 c++ 中应该使用 std::string 而不是 c 字符串,但在这种情况下,我的字符串存储在共享内存中。
EDIT
编辑
Ok, I need to add some explanation.
好的,我需要添加一些解释。
My application is getting a string from a shared memory (which is of some length), therefore it could be represented as an array of characters. If there is a bug in the library writing this string, then the string would not be zero terminated, and the strlen could fail.
我的应用程序从共享内存(有一定长度)获取一个字符串,因此它可以表示为一个字符数组。如果库中存在写入此字符串的错误,则该字符串不会以零结尾,并且 strlen 可能会失败。
采纳答案by Dennis
If you define a c-string as
如果您将 c 字符串定义为
char* cowSays = "moo";
then you autmagically get the '\0' at the end and strlen
would return 3. If you define it like:
然后你在最后自动获得 '\0' 并strlen
返回 3。如果你像这样定义它:
char iDoThis[1024] = {0};
you get an empty buffer (and array of characters, all of which are null characters). You can then fill it with what you like as long as you don't over-run the buffer length. At the start strlen
would return 0, and once you have written something you would also get the correct number from strlen
.
You could also do this:
你得到一个空缓冲区(和字符数组,所有这些都是空字符)。只要您不超过缓冲区长度,您就可以用您喜欢的内容填充它。一开始strlen
会返回 0,一旦你写了一些东西,你也会从strlen
.
你也可以这样做:
char uhoh[100];
int len = strlen(uhoh);
but that would be bad, because you have no idea what is in that array. It could hit a null character you might not. The point is that the null character is the defined standardmanner to declare that the string is finished.
Not having a null character means by definitionthat the string is not finished. Changing that will break the paradigm of how the string works. What you want to do is make up your own rules. C++ will let you do that, but you will have to write a lot of code yourself.
但这会很糟糕,因为您不知道该数组中有什么。它可能会击中您可能不会击中的空字符。关键是空字符是定义的标准方式来声明字符串完成。
根据定义,
没有空字符意味着字符串未完成。改变这将打破字符串如何工作的范式。你想做的是制定你自己的规则。C++ 可以让您这样做,但您必须自己编写大量代码。
EDITFrom your newly added info, what you want to do is loop over the array and check for the null character by hand. You should also do some validation if you are expecting ASCII characters only (especially if you are expecting alpha-numeric characters). This assumes that you know the maximum size.
If you do not need to validate the content of the string then you could use one of the strnlen
family of functions:
http://msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm
编辑从您新添加的信息中,您想要做的是遍历数组并手动检查空字符。如果您只需要 ASCII 字符(特别是如果您需要字母数字字符),您还应该进行一些验证。这假设您知道最大大小。如果您不需要验证字符串的内容,那么您可以使用以下strnlen
函数系列之一:http:
//msdn.microsoft.com/en-us/library/z50ty2zh%28v=vs.80%29.aspx
http://linux.about.com/library/cmd/blcmdl3_strnlen.htm
回答by MSalters
You've added that the string is in shared memory. That's guaranteed readable, and of fixed size. You can therefore use size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize)
(mind the extra n
in strnlen
).
您已添加该字符串在共享内存中。这保证可读,并且大小固定。因此,您可以使用size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize)
(介意额外n
的strnlen
)。
This will return MaxPossibleSize
if there's no \0
in the shared memory following input
, or the string length if there is. (The maximal possible string length is of course MaxPossibleSize-1
, in case the last byte of shared memory is the first \0
)
MaxPossibleSize
如果\0
后面的共享内存中没有,这将返回,如果有,则返回input
字符串长度。(最大可能的字符串长度当然是MaxPossibleSize-1
,以防共享内存的最后一个字节是第一个\0
)
回答by MSalters
C strings that are not null-terminated are not C strings, they are simply arrays of characters, and there is no way of finding their length.
不以空字符结尾的 C 字符串不是 C 字符串,它们只是字符数组,并且无法找到它们的长度。
回答by Andrew W. Phillips
size_t safe_strlen(const char *str, size_t max_len)
{
const char * end = (const char *)memchr(str, 'buffer[-1+sizeof(buffer)]=0 ;
x = strlen(buffer) ;
', max_len);
if (end == NULL)
return max_len;
else
return end - str;
}
回答by mattnz
Get a better library, or verify the one you have - if you can't trust you library to do what it says it will, then how the h%^&l do you expect your program to?
获得一个更好的库,或验证您拥有的库 - 如果您不能相信您的库会按照它所说的去做,那么 h%^&l 您希望您的程序如何?
Thats said, Assuming you know the length of the buiffer the string resides, what about
也就是说,假设您知道字符串所在的缓冲区的长度,那么
assert(x<-1+sizeof(buffer));
make buffer bigger than needed and you can then test the lib.
assert(x<-1+sizeof(buffer));
使缓冲区大于所需的大小,然后您可以测试该库。
// 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;
回答by edo888
If you need to get the size of shared memory, try to use
如果需要获取共享内存的大小,请尝试使用
buff[BUFF_SIZE -1] = 'int safeStrlen(char *buf, int max)
{
int i;
for(i=0;buf[i] && i<max; i++){};
return i;
}
'
Instead of using strlen you can use shm_size - 1 if you are sure that it is null terminated. Otherwise you can null terminate it by data[shm_size - 1] = '\0'; then use strlen(data);
如果您确定它是空终止的,则可以使用 shm_size - 1 而不是使用 strlen 。否则你可以通过 data[shm_size - 1] = '\0'; 然后使用 strlen(data);
回答by NoSenseEtAl
a simple solution:
一个简单的解决方案:
char cstring[3] = {'1','2','3'};
ofc this will not tell you if the string originally was exactly BUFF_SIZE-1 long or it was just not terminated... so you need xtra logic for that.
ofc 这不会告诉您字符串最初是否正好是 BUFF_SIZE-1 长,或者它只是没有终止……所以您需要 xtra 逻辑。
回答by hotplasma
How about this portable nugget:
这个便携式金块怎么样:
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 size_t strnlen_s(const char *, size_t);
termination character
pszCString[size] = '##代码##';
return pszCString;
}
回答by Spektakulatius
As Neil Butterworthalready said in his answer above: C-Strings which are not terminated by a \0 character, are no C-Strings!
正如尼尔巴特沃斯在上面的回答中已经说过的那样:不以 \0 字符终止的 C-Strings 不是 C-Strings!
The only chance you do have is to write an immutable Adaptor or something which creates a valid copy of the C-String with a \0 terminating character. Of course, if the input is wrong and there is an C-String defined like:
你唯一的机会是编写一个不可变的适配器或其他东西,它创建一个带有 \0 终止字符的 C-String 的有效副本。当然,如果输入错误并且有一个 C-String 定义如下:
##代码##will indeed result in unexpected behavior, because there can be something like 123@4x\0
in the memory now. So the result of of strlen() for example is now 6 and not 3 as expected.
确实会导致意外行为,因为123@4x\0
现在内存中可能会有类似的东西。因此,例如 strlen() 的结果现在是 6 而不是预期的 3。
The following approach shows how to create a safe C-String in any case:
以下方法显示了如何在任何情况下创建安全的 C-String:
##代码##This ensures that if you manipulate the C-String to not write on the memory of something else.
这确保如果您操作 C-String 不会写入其他内容的内存。
But this is not what you wanted. I know, but there is no other way to achieve the length of a char array without termination. This isn't even an approach. It just ensures that even if the User (or Dev) is inserting ***** to work fine.
但这不是你想要的。我知道,但是没有其他方法可以在不终止的情况下实现 char 数组的长度。这甚至不是一种方法。它只是确保即使用户(或开发人员)插入 ***** 也能正常工作。
回答by user2023370
C11 includes "safe" functions such as strnlen_s
. strnlen_s
takes an extra maximum length argument (a size_t
). This argument is returned if a null character isn't found after checking that many characters. It also returns the second argument if a null pointer is provided.
C11 包括“安全”功能,例如strnlen_s
. strnlen_s
需要一个额外的最大长度参数 (a size_t
)。如果在检查这么多字符后未找到空字符,则返回此参数。如果提供了空指针,它还返回第二个参数。
While part of C11, it is recommended that you check that your compiler supports these bounds-checking "safe" functions via its definition of __STDC_LIB_EXT1__
. Furthermore, a user must also set another macro, __STDC_WANT_LIB_EXT1__
, to 1
, before including string.h
, if they intend to use such functions. See herefor some Stack Overflow commentary on the origins of these functions, and herefor C++ documentation.
虽然是 C11 的一部分,但建议您检查您的编译器通过其__STDC_LIB_EXT1__
. 此外,用户还必须设置另一个宏,__STDC_WANT_LIB_EXT1__
以1
包括前string.h
,如果他们打算使用这些功能。见这里对这些功能的起源一些堆栈溢出的评论,并在这里为C ++文档。
GCC and Clang also support the POSIX function strnlen
, and provide it within string.h
. Microsoft too provide strnlen
which can also be found within string.h
.
GCC 和 Clang 也支持 POSIX 函数strnlen
,并在string.h
. 微软也提供strnlen
,也可以在string.h
.