Using C format specifications in C#

73 Views Asked by At

I rebuild an existing system that formats numbers using C format specifications. To be compatible with the existing system, I also have to work with the C format specifications. To keep the effort as low as possible, I tried to use the native implementation in C#. See my code example.

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int sprintf([Out] StringBuilder str, string format, params object[] arg);

public static double? CFormat(this double? value, string? format)
{
    if (string.IsNullOrWhiteSpace(format) || value == null)
        return value;

    StringBuilder stringBuilder = new StringBuilder();
    sprintf(stringBuilder, format, (double)value);
    return Convert.ToDouble(stringBuilder.ToString());
}
public static void Main()
{
    double? test1 = 137.2346243;
    string format = "%.f";

    Console.WriteLine(test1.CFormat(format));
    Console.WriteLine("Hello World");
}

However, the output is always "0". This suggests that the C library is not fully compatible with C#. Does anyone have another idea without rebuilding all possible format specifications?

1

There are 1 best solutions below

0
Nyxero On

Here is a usable example to format a nullable double using a method extension and a C format specification.

[DllImport("msvcrt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern int _snwprintf_s(
    [MarshalAs(UnmanagedType.LPWStr)] StringBuilder str,
    IntPtr bufferSize,
    IntPtr length,
    string format,
    double value
);

public static double? CFormat(this double? value, string? format)
{
    if (string.IsNullOrWhiteSpace(format) || value == null)
        return value;

    StringBuilder stringBuilder = new StringBuilder(100);
    _snwprintf_s(stringBuilder, 100, 32, format, (double)value);

    var applicableToDouble = double.TryParse(
        Encoding.UTF8.GetBytes(stringBuilder.ToString()),
        CultureInfo.InvariantCulture,
        out double result
    );

    if (!applicableToDouble)
    {
        throw new ArgumentException("The given format is not applicable to a double.", nameof(format));
    }

    return result;
}
public static void Main()
{
    double? test1 = 137.2346243;
    string format = "%.4f";

    Console.WriteLine(test1.CFormat(format));
}