5

C# 6 introduced string interpolation and a shorter way to specify the format string.

IntPtr ptr = new IntPtr(0xff);

Console.WriteLine(ptr.ToString());      // 255
Console.WriteLine(ptr.ToString("x"));   // ff

Console.WriteLine($"0x{ptr.ToString("x")}"); // 0xff
Console.WriteLine($"0x{ptr:x}"); //0x255

Why the two last lines output a different result ? Am I missing something ?

Try it with DotnetFiddle

As a side note here is the source code of IntPtr ToString() in dotnet core :

public unsafe  String ToString(String format) 
    {
        #if WIN32
            return ((int)m_value).ToString(format, CultureInfo.InvariantCulture);
        #else
            return ((long)m_value).ToString(format, CultureInfo.InvariantCulture);
        #endif
    }
KVM
  • 878
  • 3
  • 13
  • 22

2 Answers2

7

Your example code:

Console.WriteLine($"0x{ptr:x}");

Is equivalent to its string.Format brother:

Console.WriteLine(string.Format("0x{0:x}", ptr));

When applying your format string "x", string interpolation / string format ultimately reaches this line of code:

IFormattable formattableArg = arg as IFormattable;

Unfortunately, while IntPtr has a custom format ToString() method, it doesn't implement IFormattable, so it's basic .ToString() method is called and the format string is discarded.

See this question for more information

As vasily.sib suggested, you can use $"0x{(int)ptr:x}" instead.

Try my example.

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • Since IntPtr doesn't implement IFormattable, why does `ptr.ToString("x")` formats to hexadecimal ? – KVM Mar 27 '20 at 11:36
  • 1
    @Kvm As I explained, it has a custom ToString method that takes a format string. I even provided a link to it in my answer so that you can read its code. – ProgrammingLlama Mar 27 '20 at 12:09
  • "the format string is discarded" is something that the Framework obviously ought to detect and warn about, preferably at compile time (since interpolated string are already undergoing rather heavy transformation by the compiler), but if not then it ought to spit out some warning at runtime. – Ben Voigt Jun 27 '22 at 21:17
0

As documentation says:

https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings

For example, use "X" to produce "ABCDEF", and "x" to produce "abcdef". This format is supported only for integral types.

Pointer is not integral type. For example:

string.Format("{0:x}", ptr)

also returns 255.

fdafadf
  • 809
  • 5
  • 13
  • Since IntPtr is not an integral type, then why does ptr.ToString("x") formats to hexadecimal ? – KVM Mar 27 '20 at 11:39
  • If you want know more than the documentation, for example you can check an implementation of ToString method of IntPtr class. `public unsafe string ToString(string format) { return ((long)m_value).ToString(format, CultureInfo.InvariantCulture); }` It uses internally integral type (long). – fdafadf Mar 27 '20 at 12:04
  • Taking this line of reasoning one step further, "pointer is not *numeric* type", and so that documentation page is just as inapplicable as "standard date/time format strings". – Ben Voigt Jun 27 '22 at 21:18