10

So I've looked around for how to convert a string to a short and found a lot on how to convert a string to an integer. I would leave a question as a comment on those threads, but I don't have enough reputation. So, what I want to do is convert a string to a short, because the number should never go above three or below zero and shorts save memory (as far as I'm aware).

To be clear, I'm not referring to ASCII codes.

Another thing I want to be able to do is to check if the conversion of the string to the short fails, because I'll be using a string which consists of a users input.

I know I can do this with a while loop, but if there's a built in function to do this in C++ that would be just as, or more, efficient than a while loop, I would love to hear about it.

Logan Kling
  • 569
  • 2
  • 6
  • 19
  • 1
    Doesn't `short s; std::istringstream strm("100"); strm >> s;` work? – timrau Feb 13 '15 at 03:45
  • 1
    `shorts save memory` I think the real question here is why do you think you need to save memory? – user657267 Feb 13 '15 at 03:48
  • 1
    @timrau Which is more efficient, the code you proposed, or a lexical cast? – Logan Kling Feb 13 '15 at 03:52
  • 2
    @user657267 I obsess over program efficiency simply because I'm such a perfectionist. – Logan Kling Feb 13 '15 at 03:52
  • 1
    @LarryK `I obsess over program efficiency simply because I'm such a perfectionist` Well, did you write code to ensure that your rule is maintained, namely `the number should never go above three or below zero`? – PaulMcKenzie Feb 13 '15 at 03:54
  • 1
    @PaulMcKenzie I'm going to use that check along with a check to see that the conversion works so that if either of those cases return false I can prompt the user to re-enter. – Logan Kling Feb 13 '15 at 03:57
  • 2
    @LarryK As with everything there's a tradeoff, there will probably be little difference in performance between using `short`s and `int`s unless you are using long arrays / structs with these types and cache comes into play. You should start off using `int`s and only consider something else if profiling suggests you should. When programming you should consider *your* efficiency first, is it really worth your time to obsess over issues that may have almost no impact? – user657267 Feb 13 '15 at 04:04
  • 1
    @user657267 These issues may have almost no impact, but when I write larger programs, won't most of these accumulate to have a significant impact? – Logan Kling Feb 13 '15 at 04:11
  • 1
    @LarryK It's hard to make blanket statements but if you're talking about using `short`s in place of `int`s for things like function parameters and local variables then it will make no difference whatsoever. With my compiler and assembler (GCC 5 on OSX) calling a function that takes a `short` instead of an `int` results in an extra byte of assembly code for the instruction so even the (already minuscule) space saving factor isn't worth the effort, unless you're programming something embedded and every single byte really counts. – user657267 Feb 13 '15 at 05:20
  • In my case, I'm obsessed with preventing my program to end up in an invalid state. If I want the user to enter a port (65536 possibilities (or a `short`)), I don't want to store an `int` because the user could enter an invalid port. Sure, I could use runtime validation, but I feel WAY safer with compile-time validation (AKA Mr. Good Ol' Static Type System): mistakes are caught before the program even starts. – ljleb Aug 17 '20 at 03:44

4 Answers4

14

Basically, an std::stos function is missing for unknown reasons, but you can easily roll your own. Use std::stoi to convert to int, check value against short boundaries given by e.g. std::numeric_limits<short>, throw std::range_error if it's not in range, otherwise return that value. There.

If you already have the Boost library installed you might use boost::lexical_cast for convenience, but otherwise I would avoid it (mainly for the verbosity and library dependency, and it's also a little inefficient).

Earlier boost::lexical_cast was known for not being very efficient, I believe because it was based internally on stringstreams, but as reported in comments here the modern version is faster than conversion via stringstream, and for that matter than via scanf.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 1
    An example piece of code would be helpful. Especially one that uses a while or do while loop to catch the range error. – Logan Kling Feb 13 '15 at 04:00
  • 3
    @LarryK: I won't catch your fish for you, or prepare it for you. Given your comment about wanting it done for you, you very much need to learn to fish and prepare a fish. The best way to do that is to do it. – Cheers and hth. - Alf Feb 13 '15 at 04:02
  • 1
    Nice clarification about the efficiency of the lexical cast! That's something I obsess over. Thank you. – Logan Kling Feb 13 '15 at 04:02
  • @LarryK: Hm. As it happens I was wrong about that parenthetical remark: things have changed. Thus I marked it as deleted and added more up-to-date info. ;-) – Cheers and hth. - Alf Feb 13 '15 at 04:09
  • That page links to tests that were done on relatively old compiler versions. To call it efficient without a disclaimer is disingenuous. –  Feb 13 '15 at 04:13
  • @remyabel Meh, I'm extremely doubtful that optimizing iostreams performance is high on any standard library maintainer's priority list. – T.C. Feb 13 '15 at 04:31
  • 1
    There's another SO post somewhere where the guy does benchmarks on all the different string-to-int routines – M.M Feb 13 '15 at 08:43
5

An efficient way is to use boost::lexical_cast:

short myShort = boost::lexical_cast<short>(myString);

You will need to install boost library and the following include: #include <boost/lexical_cast.hpp>

You should catch bad_lexical_cast in case the cast fails:

    try
    {
        short myShort = boost::lexical_cast<short>(myString);
    }
    catch(bad_lexical_cast &)
    {
        // Do something
    }
Jérôme
  • 8,016
  • 4
  • 29
  • 35
  • How does the efficiency of a lexical cast compare to `short s; std::istringstream strm("100"); strm >> s;`? – Logan Kling Feb 13 '15 at 03:54
  • 1
    @LarryK `lexical_cast` is [about 20 times faster](http://www.boost.org/doc/libs/1_57_0/doc/html/boost_lexical_cast/performance.html). – Drew Dormann Feb 13 '15 at 04:01
3

You can also use ssprintf with the %hi format specifier.

Example:

short port;
char szPort[] = "80";

sscanf(szPort, "%hi", &port);
John Doe
  • 120
  • 8
  • I actually just learned about these modifiers a few weeks ago, but I really appreciate your answer! I've found the `h` & `hh` modifiers to be incredibly useful, & not just for `ssprintf()`. – Larrimus Nov 03 '17 at 20:32
1

the number should never go above three or below zero

If you really really need to save memory, then this will also fit in a char (regardless whether char is signed or unsigned).

Another 'extreme' trick: if you can trust there are no weird things like "002" then what you have is a single character string. If that is the case, and you really really need performance, try:

char result = (char)( *ptr_c_string - '0' );
Bert Bril
  • 56
  • 1