Jump to content
  • Advertisement
Sign in to follow this  
jt.tarigan

C++: how does strncpy_s work?

Recommended Posts

Posted (edited)

Hi, 

I'm having trouble to understand the behavior of strncpy_s. So I have char* dst which is later defined as an array of char with the size of 1024 (max possible length). I tried to fill with chars from char* src with the length of 442. So I use strncpy_s like this:

strncpy_s(dst, 442,src, 442);

It always returns an error (L'Buffer is too small). I don't get it since the destination length and source is the same, and dst is actually larger than src. But when I changed the code to this

strncpy_s(dst, 1024,src, 442);

the code runs without any error. Of course, I can simply put the maximum number (1024) on the destination length, but I wonder how it actually works. Can anyone help me with this?

Thank you

Edited by jt.tarigan

Share this post


Link to post
Share on other sites
Advertisement

Why are you manipulating zero-terminated char buffers, instead of using std::string?

 

Share this post


Link to post
Share on other sites

I couldn't care less about the reputation system on these forums, but it would be better if the people who are downvoting my question could explain what they think is wrong with it. That way we can have a conversation.

The point of the question is in part to suggest a different approach to the OP, and in part it's an honest question: There might be advantages to this way of handling strings that I am not aware of. We could all learn something from the discussion.

 

Share this post


Link to post
Share on other sites

I decided to keep using this one:

strncpy_s(dst, 1024,src, 442);

I've read somewhere that this is probably the best solution since there is no performance hiccup. I only need to make sure that the source does not exceed the length of the destination. Thanks for the reply :)

Share this post


Link to post
Share on other sites
On 3/27/2019 at 8:06 PM, jt.tarigan said:

It always returns an error (L'Buffer is too small). I don't get it since the destination length and source is the same, and dst is actually larger than src. But when I changed the code to this

If there are 442 characters in a string (the length of actual characters, not including the null terminator), then the destination buffer needs to have enough space to store 443 characters so that it can write a null terminator at the end of the string. Some string handling functions would simply truncatthe string in this situation (drop the last character and replace it with the null terminator), while others would simple not write the null terminator at all and leave you in a very dangerous situation, but strncpy_s is specified to do nothing and return an error when the destination buffer is too small. The docs are here: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strncpy-s-strncpy-s-l-wcsncpy-s-wcsncpy-s-l-mbsncpy-s-mbsncpy-s-l?view=vs-2017

When doing manual C-style string manipulation, it's important to know which of these functions deals with length in characters including the terminator, which ones work with length in characters without the terminator, and which ones deal with length in bytes of a memory allocation. Always check the documentation.

1 hour ago, jt.tarigan said:

I decided to keep using this one:


strncpy_s(dst, 1024,src, 442);

I've read somewhere that this is probably the best solution

To be frank, that's voodoo coding / cargo cult coding, and doing random things with raw byte array management that seems to work without deep understanding of why, is not a recipe for stable software. Memory corruption lies that way...

If dst is actually a static size of 1kb though, then yeah, this is correct -- "copy a C string of length 442 (not counting the terminator) into this 1kb allocation".

If dst is a fixed size array, like "char dst[1024]", then you can avoid human error by calling "strncpy_s(dst, src, length)" and the destination size of 1025 will be inferred automatically.

18 hours ago, alvaro said:

Why are you manipulating zero-terminated char buffers, instead of using std::string?

I couldn't care less about the reputation system on these forums, but it would be better if the people who are downvoting my question could explain what they think is wrong with it. That way we can have a conversation.

Sorry, I downvoted this because it's a straightforward question of 'how does this account function work', and that function has many uses in places where std::string is a shitty solution.

But, I didn't notice the OP has tagged this as a C++ question and is going to just arbitrarily tweak numbers to make it work, so, yeah, using std::string is entirely appropriate here 😅

Share this post


Link to post
Share on other sites
2 hours ago, Hodgman said:

Sorry, I downvoted this because it's a straightforward question of 'how does this account function work', and that function has many uses in places where std::string is a shitty solution.

While I agree with you globally (this might be faster, and you know exactly what you do and when you do it), it is also worth mentioning that keeping using low-level functions to play with strings will definitely lead to security issues. It might not be the case of the OP thought, but anyone has to keep in mind that 90% of network breaches are due to buffer overflow and other misuses of buffers. And since nowadays most games have any network / internet connection, I believe that the safest advice to give to new comers and not very experienced programmer is to use safe tools.

That's just my two cents.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!