D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 9797 - to!int() cannot convert hexadecimal numbers
Summary: to!int() cannot convert hexadecimal numbers
Status: RESOLVED WONTFIX
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-03-23 10:14 UTC by Sarath Kumar Kodali
Modified: 2020-03-21 03:56 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Sarath Kumar Kodali 2013-03-23 10:14:23 UTC
$ cat conv_bug.d
import std.conv;

void main()
{
        auto var = to!int("0x123");
}
$ rdmd conv_bug.d
std.conv.ConvException@/usr/include/dmd/phobos/std/conv.d(1612): Unexpected 'x' when converting from type string to type int
Comment 1 Andrej Mitrovic 2013-03-23 10:39:40 UTC
This might end up being rejected like Issue 7692. See comment https://github.com/D-Programming-Language/phobos/pull/835#discussion_r1764414.
Comment 2 Sarath Kumar Kodali 2013-04-15 19:25:49 UTC
(In reply to comment #1)
> This might end up being rejected like Issue 7692. See comment
> https://github.com/D-Programming-Language/phobos/pull/835#discussion_r1764414.

The reason given to close issue 7692 is wrong. In D a hexadecimal number is prefixed with 0x. Not being able to recognize a valid D hexadecimal number is a bug in to!int().

Below is what C's strtol() does and parse!int() should behave same.

value = strtol("0xyz", &leftover, 0);   // value == 0, leftover == "xyz"
value = strtol("0xyz", &leftover, 16);   // value == 0, leftover == "xyz"
value = strtol("0x0x", &leftover, 0);   // value == 0, leftover == "x"
value = strtol("0x0x", &leftover, 16);   // value == 0, leftover == "x"
value = strtol("0x0x", &leftover, 10);   // value == 0, leftover == "x0x"
value = strtol("abcd", &leftover, 0);   // value == 0, leftover == "abcd"
value = strtol("abcd", &leftover, 16);   // value == 0xabcd, leftover == ""
Comment 3 Cauterite 2015-11-06 12:44:03 UTC
I can see only one reasonable(ish) solution here:
Patch toImpl() to detect prefixes like "0x" and "0b", so it calls parse() with the appropriate radix. This may not be as much of a problem as patching parse() itself, since toImpl() either parses the whole input successfully or throws.

However, if the caller is not fully aware that to() accepts these alternative number syntaxes, it could easily cause subtle bugs. Additionally, having parse() and to() operate differently doesn't sit right with me.

The only other option I can think of would be to provide a separate function specifically for parsing D-style numeric literals, but this is out of the scope of std.conv

Unless anyone has a better idea, I suggest WONTFIX. It's not an *especially* common problem, and parse() with explicit radix makes it trivial for callers to deal with it themselves.
Comment 4 basile-z 2015-11-07 02:00:55 UTC
Agree, furthemore there are others prefix/suffix notations:

- 12345678h: several hex editors , IDA
- #12345678: colors, html, css
- $12345678: Pascal
- 0X or 0x
- and maybe others...

so even if 0x is handled ,there are several cases where the user has to parse the  prefix/suffix by hand anyway.
Comment 5 basile-z 2016-04-02 01:24:11 UTC
> In D a hexadecimal number is prefixed with 0x. Not being able to recognize a valid D hexadecimal number is a bug in to!int().

And then even if done, someone will come and report that `to()` is not able to convert "0x1_2_3_4_P5" (valid D hexadecimal litteral)! 
So your argument is invalid.
Comment 6 Jonathan M Davis 2016-04-02 15:57:26 UTC
I would point out that while to!int("0x123"); isn't going to work, to!int("123", 16); will. e.g.

    import std.conv;

    void main()
    {
        auto str = to!string(42, 16);
        assert(str == "2A", str);
        auto i = to!int(str, 16);
        assert(i == 42);
    }

So, if you check for 0x and strip it off before feeding the string to to!int, then it will do the conversion. It just won't work with the prefix on it. And while having to!int check for the prefix as well as anything else that's valid in a numeric literal in D might be nice in some cases, it would slow down to!int for everything else, which really isn't a good tradeoff given how much to!int is used. A conversion function specifically for literals might make sense, but I have to concur that doing it with std.conv.to isn't worth it.