Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


replacing sprintf_s trouble


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 TheComet   Crossbones+   -  Reputation: 1640

Like
0Likes
Like

Posted 04 February 2014 - 06:14 AM

Hi,

 

So I received some code and a memo saying, I quote, "problems with overflows". I check it out, and I see something along the lines of the following:

char cmdstr[20];
sprintf_s(cmdstr,"STAS %d,%d\n",min(m_fstart,m_fstart2),max(m_fstop,m_fstop2));
viPrintf(vi,cmdstr);
viPrintf(vi,"CHAN1\n");
// ---SNIP---

Immediately, I changed it to this:

std::stringstream cmdstr;
cmdstr << "STAS " << min(m_fstart,m_fstart2) << "," << max(m_fstop,m_fstop2) << std::endl;
viPrintf(vi,cmdstr.str().c_str()); // viPrintf is not const-correct, i.e. cmdstr is declared as "char*", not "const char*"

HOWEVER, as stated in the comments above, the function "viPrintf" is not const correct. Even though it only reads form "cmdstr", the function argument was declared as "char*" and the compiler will refuse to compile it.

 

I cannot change viPrintf because it is part of an external library I don't have access to.

 

How can I go about converting a string stream to a non-const char array? The thought of copying it into a new std::string object and using &str.at(0) crossed my mind, but that seems a little... I don't know, is there a better way?


Edited by TheComet, 04 February 2014 - 06:19 AM.

YOUR_OPINION >/dev/null

Sponsor:

#2 Mona2000   Members   -  Reputation: 623

Like
1Likes
Like

Posted 04 February 2014 - 06:28 AM

const_cast<char *>(cmdstr.str().c_str())



#3 TheComet   Crossbones+   -  Reputation: 1640

Like
0Likes
Like

Posted 04 February 2014 - 06:39 AM

An additional question, is it dangerous to do that if viPrintf() were to change the char array you provide it with? cmdstr.str().c_str() is const because its not meant to be written to.


Edited by TheComet, 04 February 2014 - 06:44 AM.

YOUR_OPINION >/dev/null

#4 BitMaster   Crossbones+   -  Reputation: 4422

Like
1Likes
Like

Posted 04 February 2014 - 07:01 AM

If you are confident viPrintf is indeed not changing anything (that is, it's missing a const but behaves as it is there), then you don't have any problems. Something like a const_cast should always be properly commented though.

If you are not sure and viPrintf might change some characters then it will (most likely) still work on all compilers and standard libraries although it's technically invoking undefined behavior. If viPrintf tries messing with characters beyond the C string length (for example because it assumes it always has at least 20 characters to work with) then you are in troubles.

If you want to be on the safe side, allocate a new C string of the correct size (plus safety margin as desired), copy the content of cmdstr.str() in there, and pass that C string to viPrintf.

Edited by BitMaster, 04 February 2014 - 07:02 AM.


#5 TheComet   Crossbones+   -  Reputation: 1640

Like
0Likes
Like

Posted 04 February 2014 - 07:04 AM

Alright, thank you very much! Didn't know about const_cast until now.


YOUR_OPINION >/dev/null

#6 Aardvajk   Crossbones+   -  Reputation: 6181

Like
0Likes
Like

Posted 04 February 2014 - 08:51 AM

If the function turns out to modify, don't fall back on manually allocating the memory, just use a vector:

std::string s = whatever();

std::vector<char> v(s.begin(), s.end());
viPrintf(v.data());

Then you still have exception safety and so on if viPrintf throws something.

 

[EDIT] Hmm, actually, that probably doesn't copy the null character but you get the idea...


Edited by Aardvajk, 04 February 2014 - 08:52 AM.


#7 BitMaster   Crossbones+   -  Reputation: 4422

Like
0Likes
Like

Posted 04 February 2014 - 08:57 AM

Yeah, the null character (and the potential for needing some extra space) ruin the vector. Once you cannot use the iterator range constructor the vector is just a bit awkward (especially pre-C++11 without std::vector::data). Personally I would have gone with std::unique_ptr or boost::scoped_array for the job.

#8 TheComet   Crossbones+   -  Reputation: 1640

Like
0Likes
Like

Posted 04 February 2014 - 08:59 AM

Thanks for the help! The solution I went with was:

std::stringstream cmdstr;
cmdstr << "STAS " << min(m_fstart,m_fstart2) << "," << max(m_fstop,m_fstop2) << std::endl;
viPrintf(vi,const_cast<char*>(cmdstr.str().c_str()));

It turns out viPrintf() really doesn't modify the data, it only reads from it.


YOUR_OPINION >/dev/null

#9 TheComet   Crossbones+   -  Reputation: 1640

Like
0Likes
Like

Posted 04 February 2014 - 09:15 AM

Another way of potentially doing it to avoid a const cast would be:

viPrintf(vi, &cmdstr.str().at(0));

Obviously you'd need to null-terminate the stream before you do that:

cmdstr << '\0';

I think const_cast is cleaner and less error prone.


Edited by TheComet, 04 February 2014 - 09:15 AM.

YOUR_OPINION >/dev/null




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS