strlen 有安全版本吗?
std::strlen 不处理不是 \0 的 C 字符串终止。有安全版本吗?
PS 我知道在 c++ 中应该使用 std::string 而不是 c 字符串,但在这种情况下我的字符串存储在共享内存中。
编辑
好的,我需要添加一些解释。
我的应用程序正在从共享内存(具有一定长度)获取字符串,因此它可以表示为字符数组。如果编写此字符串的库中存在错误,则该字符串不会以零结尾,并且 strlen 可能会失败。
std::strlen doesn't handle c strings that are not \0 terminated. Is there a safe version of it?
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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
您已添加该字符串位于共享内存中。这是保证可读且大小固定的。因此,您可以使用 size_t MaxPossibleSize = startOfSharedMemory + sizeOfSharedMemory - input; strnlen(input, MaxPossibleSize)(注意
strnlen
中额外的n
)。如果
input
之后的共享内存中没有\0
,则返回MaxPossibleSize
,如果有,则返回字符串长度。 (最大可能的字符串长度当然是MaxPossibleSize-1
,以防共享内存的最后一个字节是第一个\0
)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 extran
instrnlen
).This will return
MaxPossibleSize
if there's no\0
in the shared memory followinginput
, or the string length if there is. (The maximal possible string length is of courseMaxPossibleSize-1
, in case the last byte of shared memory is the first\0
)不以 null 结尾的 C 字符串不是 C 字符串,它们只是字符数组,并且无法找到它们的长度。
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 字符串,
那么你会自动在末尾得到 '\0' 并且
strlen
将返回 3。如果你这样定义它:你会得到一个空缓冲区(和字符数组,所有这些都是空字符)。然后,只要不超过缓冲区长度,您就可以用您喜欢的内容填充它。一开始
strlen
会返回0,一旦你写完一些东西,你也会从strlen
得到正确的数字。您也可以这样做:
但这会很糟糕,因为您不知道该数组中有什么。它可能会击中空字符,而您可能不会击中。要点是空字符是声明字符串结束的定义的标准方式。
没有空字符意味着根据定义字符串尚未完成。改变这一点将打破字符串工作的范式。你想做的就是制定自己的规则。 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
If you define a c-string as
then you autmagically get the '\0' at the end and
strlen
would return 3. If you define it like: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 fromstrlen
.You could also do this:
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 standard manner to declare that the string is finished.
Not having a null character means by definition that 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.
EDIT
From 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
是的,从 C11 开始:
size_t strnlen_s( const char *str, size_t strsz );
位于
Yes, since C11:
size_t strnlen_s( const char *str, size_t strsz );
Located in
<string.h>
获得一个更好的库,或者验证您拥有的库 - 如果您不能相信您的库会按照它所说的去做,那么您希望您的程序如何做?
也就是说,假设您知道字符串所在的缓冲区的长度,那么
使缓冲区大于所需的大小,然后您就可以测试该库了。
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?
Thats said, Assuming you know the length of the buiffer the string resides, what about
make buffer bigger than needed and you can then test the lib.
C11 包括“安全”函数,例如 strnlen_s。
strnlen_s
采用额外的最大长度参数(size_t
)。如果在检查这么多字符后未找到空字符,则返回此参数。如果提供了空指针,它还会返回第二个参数。虽然是 C11 的一部分,但建议您通过
__STDC_LIB_EXT1__
的定义来检查您的编译器是否支持这些边界检查“安全”函数。此外,如果用户打算使用此类函数,则在包含string.h
之前,还必须将另一个宏__STDC_WANT_LIB_EXT1__
设置为1
。有关这些函数起源的一些 Stack Overflow 评论,请参阅此处,以及此处获取 C++ 文档。GCC 和 Clang 还支持 POSIX 函数
strnlen
,并在string.h
中提供它。 Microsoft 也提供了strnlen
,它也可以在string.h
中找到。C11 includes "safe" functions such as
strnlen_s
.strnlen_s
takes an extra maximum length argument (asize_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.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__
, to1
, before includingstring.h
, if they intend to use such functions. See here for some Stack Overflow commentary on the origins of these functions, and here for C++ documentation.GCC and Clang also support the POSIX function
strnlen
, and provide it withinstring.h
. Microsoft too providestrnlen
which can also be found withinstring.h
.您需要对字符串进行编码。例如:
如果您知道共享内存位置的第一个 sizeof(size_t) 字节是字符数组的大小,则可以接受任何字符数组。当你想以这种方式链接数组时,事情会变得很棘手。
最好相信您的另一端终止它的字符串或滚动您自己的 strlen,该 strlen 不会超出共享内存段的边界(前提是您至少知道该段的大小)。
You will need to encode your string. For example:
You can then accept any array of characters if you know the first sizeof(size_t) bytes of the shared memory location is the size of the char array. It gets tricky when you want to chain arrays this way.
It's better to trust your other end to terminate it's strings or roll your own strlen that does not go outside the bounderies of the shared memory segment (providing you know at least the size of that segment).
如果您需要获取共享内存的大小,请尝试使用
shm_size - 1(如果您确定它是 null 终止的)而不是使用 strlen 。否则你可以通过 data[shm_size - 1] = '\0'; 来终止它然后使用 strlen(数据);
If you need to get the size of shared memory, try to use
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);
这个便携式金块怎么样:
How about this portable nugget:
正如 Neil Butterworth 在上面的回答中已经说过的那样:不以 \0 字符结尾的 C 字符串不是 C 字符串!
您唯一的机会是编写一个不可变的适配器或创建带有 \0 终止字符的 C 字符串的有效副本的东西。当然,如果输入错误并且有一个像这样定义的C字符串:
确实会导致意外的行为,因为现在内存中可能存在类似
123@4x\0
的东西。因此,例如 strlen() 的结果现在是 6,而不是预期的 3。以下方法展示了如何在任何情况下创建安全的 C 字符串:
这可以确保您操作 C 字符串时不会写入其他内容的内存。
但这不是你想要的。我知道,但是没有其他方法可以在不终止的情况下实现 char 数组的长度。这甚至不是一种方法。它只是确保即使用户(或开发人员)插入 ***** 也能正常工作。
As Neil Butterworth already said in his answer above: C-Strings which are not terminated by a \0 character, are no 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:
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.The following approach shows how to create a safe C-String in any case:
This ensures that if you manipulate the C-String to not write on the memory of something else.
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.
一个简单的解决方案:
ofc 这不会告诉你字符串最初是否正好是 BUFF_SIZE-1 长或者它只是没有终止......所以你需要额外的逻辑。
a simple solution:
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.