printf-like function for C#
up vote
-2
down vote
favorite
I want to write function for C#, which will be similar to sprintf(3) and vsnprintf(3) functions in C (or similar to "format" command in Tcl). Currently I have some success with it, but still have a few questions.
Below is the source code. Class "Format" contains few public functions, which accepts variable arguments list (but no more than 7 arguments, see below) and produce formatted string. This is analog of sprintf(3) function. Also function "format" may accept C# tuple, which should hold format string in first element, and arguments for format string in other elements -- this is analog of vsprintf(3) function.
Unfortunately, here I have two major limitations:
1) I can't pass more than seven arguments to format() function, because arguments passed in C# tuple, and tuple can't have more than eight elements (first element is format string itself, this is needed because empty tuples unavailable in C#). I hope to obtain some suggestions, how can I improve my format() function to avoid this limitation.
2) Another major limitation, that not all types can be passed to C# template. Especially, I can't pass pointers to format function (in this case I will got following error: "error CS0306: The type 'int*' may not be used as a type argument"). This is C# limitation? It's possible to rewrite format() function(s) to avoid this limitation?
Another major inconvenience, is that I should open some particular library name, and use C function name, which is different for different operation systems:
for windows I should use "msvcrt.dll" and "_snprintf";
for linux I should use "libc.so.6" and "snprintf";
for linux on embedded platform C-library name might have different name...
It's possible to define which library should be opened at runtime, or extern functions marshalling might be determined only at compile time? So, I see two variants possible here:
1) I need produce different DLL's for different target platforms;
2) Or I can decide at runtime, which function name and libc-library should be used?
I not understood, how can I rewrite the code for first or second variant. Also it looks very inconvenient to have knowledge about libc name. Why just not call dlsym("snprintf") ?
Another question, I trying limit using of dynamic memory, but looks It's impossible to avoid allocating few String and StringBuilder classes on heap. This is looking scary, because when programming on C/C++ it's possible to do almost all work without dynamic memory allocation. May be somebody suggests me, how to improve format() functions to avoid dynamic memory allocation.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace FK0
using Args = ITuple;
public class Format
// const string LIBC = "msvcrt.dll"; //"libc.so";
// const string FUNC = "_snprintf";
const string LIBC = "libc.so.6";
const string FUNC = "snprintf";
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I4)] int a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I8)] long a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, double a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.LPStr)]string a1);
// function returns length of next format segment (string, copied as is, or single format spec.)
static private int parse_format(string fmt, int pos)
int p = fmt.IndexOf('%', pos);
if (p == -1) return fmt.Length - pos; // copy to end of string
else if (p != pos) return p - pos; // copy till %
char fmt_term = 'd','i','o','u','x','X','e','E','f','F','g','G','a','A','c','s','p','n','%' ;
int e = fmt.IndexOfAny(fmt_term, p + 1);
if (e == -1) throw new System.ArgumentException("invalid format string");
return e - p + 1; // format specifier length
// call real `snprintf(3)' from C-library, marshal arguments appropriately
static private int call_snprintf(ref StringBuilder res, int len, StringBuilder fmt, Object arg)
arg is IntPtr) // XXX can't pass pointer to template!!!
return snprintf(res, (IntPtr)len, fmt, ((IntPtr)arg).ToInt64());
//else if (arg.GetType()
else
return snprintf(res, (IntPtr)len, fmt, Convert.ToInt32(arg));
// vsnprintf-like function (accepts all arguments in tuple)
static public string format(Args args)
if (! (args[0] is string)) // check, that first argument is string
throw new System.ArgumentException("wrong string format type");
// first pass
// compute number of arguments, size of output string and max size of formatted output
string fmt = args[0].ToString();
StringBuilder ns = null, fs = new StringBuilder();
int total_len = 0, maxlen = 0, narg = 1;
int pos = 0;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
int flen = call_snprintf(ref ns, 0, fs, args[narg]);
if (flen == -1) throw new System.ArgumentException("wrong format string");
total_len += flen;
if (flen > maxlen) maxlen = flen;
narg++;
else // compute size of literal part
total_len += len;
pos += len;
if (narg != args.Length)
throw new System.ArgumentException("incorrect # of arguments for format string");
// second pass
// print each argument separately
var result = new StringBuilder(total_len);
var part = new StringBuilder(maxlen + 1); // include terminating zero
pos = 0; narg = 1;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
call_snprintf(ref part, part.Capacity, fs, args[narg++]);
result.Append(part);
Console.WriteLine(part);
else // copy literal part as is
result.Append(fmt, pos, len);
pos += len;
return result.ToString();
// C# have no vararg templates, as C++03, also max size of tuple limited to 8 elements,
// also impossible to create empty tuple, so maximum number arguments limited to 7 (plus format string as 0-th element).
static public string format<T1, T2, T3, T4, T5, T6, T7>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6, a7));
static public string format<T1, T2, T3, T4, T5, T6>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6));
static public string format<T1, T2, T3, T4, T5>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5));
static public string format<T1, T2, T3, T4>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4)
return format(Tuple.Create(fmt, a1, a2, a3, a4));
static public string format<T1, T2, T3>(string fmt, T1 a1, T2 a2, T3 a3)
return format(Tuple.Create(fmt, a1, a2, a3));
static public string format<T1, T2>(string fmt, T1 a1, T2 a2)
return format(Tuple.Create(fmt, a1, a2));
static public string format<T1>(string fmt, T1 a1)
return format(Tuple.Create(fmt, a1));
static public string format(string fmt)
return format(Tuple.Create(fmt));
;
public class Program
unsafe public static void Main()
// System.Threading.Thread.Sleep(100000);
int z = 123;
int* y = &z;
IntPtr v = (IntPtr)y;
string s = FK0.Format.format("%p %d %d", v, *y, z);
Console.WriteLine(s);
c# .net printf clr coreclr
|
show 8 more comments
up vote
-2
down vote
favorite
I want to write function for C#, which will be similar to sprintf(3) and vsnprintf(3) functions in C (or similar to "format" command in Tcl). Currently I have some success with it, but still have a few questions.
Below is the source code. Class "Format" contains few public functions, which accepts variable arguments list (but no more than 7 arguments, see below) and produce formatted string. This is analog of sprintf(3) function. Also function "format" may accept C# tuple, which should hold format string in first element, and arguments for format string in other elements -- this is analog of vsprintf(3) function.
Unfortunately, here I have two major limitations:
1) I can't pass more than seven arguments to format() function, because arguments passed in C# tuple, and tuple can't have more than eight elements (first element is format string itself, this is needed because empty tuples unavailable in C#). I hope to obtain some suggestions, how can I improve my format() function to avoid this limitation.
2) Another major limitation, that not all types can be passed to C# template. Especially, I can't pass pointers to format function (in this case I will got following error: "error CS0306: The type 'int*' may not be used as a type argument"). This is C# limitation? It's possible to rewrite format() function(s) to avoid this limitation?
Another major inconvenience, is that I should open some particular library name, and use C function name, which is different for different operation systems:
for windows I should use "msvcrt.dll" and "_snprintf";
for linux I should use "libc.so.6" and "snprintf";
for linux on embedded platform C-library name might have different name...
It's possible to define which library should be opened at runtime, or extern functions marshalling might be determined only at compile time? So, I see two variants possible here:
1) I need produce different DLL's for different target platforms;
2) Or I can decide at runtime, which function name and libc-library should be used?
I not understood, how can I rewrite the code for first or second variant. Also it looks very inconvenient to have knowledge about libc name. Why just not call dlsym("snprintf") ?
Another question, I trying limit using of dynamic memory, but looks It's impossible to avoid allocating few String and StringBuilder classes on heap. This is looking scary, because when programming on C/C++ it's possible to do almost all work without dynamic memory allocation. May be somebody suggests me, how to improve format() functions to avoid dynamic memory allocation.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace FK0
using Args = ITuple;
public class Format
// const string LIBC = "msvcrt.dll"; //"libc.so";
// const string FUNC = "_snprintf";
const string LIBC = "libc.so.6";
const string FUNC = "snprintf";
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I4)] int a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I8)] long a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, double a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.LPStr)]string a1);
// function returns length of next format segment (string, copied as is, or single format spec.)
static private int parse_format(string fmt, int pos)
int p = fmt.IndexOf('%', pos);
if (p == -1) return fmt.Length - pos; // copy to end of string
else if (p != pos) return p - pos; // copy till %
char fmt_term = 'd','i','o','u','x','X','e','E','f','F','g','G','a','A','c','s','p','n','%' ;
int e = fmt.IndexOfAny(fmt_term, p + 1);
if (e == -1) throw new System.ArgumentException("invalid format string");
return e - p + 1; // format specifier length
// call real `snprintf(3)' from C-library, marshal arguments appropriately
static private int call_snprintf(ref StringBuilder res, int len, StringBuilder fmt, Object arg)
arg is IntPtr) // XXX can't pass pointer to template!!!
return snprintf(res, (IntPtr)len, fmt, ((IntPtr)arg).ToInt64());
//else if (arg.GetType()
else
return snprintf(res, (IntPtr)len, fmt, Convert.ToInt32(arg));
// vsnprintf-like function (accepts all arguments in tuple)
static public string format(Args args)
if (! (args[0] is string)) // check, that first argument is string
throw new System.ArgumentException("wrong string format type");
// first pass
// compute number of arguments, size of output string and max size of formatted output
string fmt = args[0].ToString();
StringBuilder ns = null, fs = new StringBuilder();
int total_len = 0, maxlen = 0, narg = 1;
int pos = 0;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
int flen = call_snprintf(ref ns, 0, fs, args[narg]);
if (flen == -1) throw new System.ArgumentException("wrong format string");
total_len += flen;
if (flen > maxlen) maxlen = flen;
narg++;
else // compute size of literal part
total_len += len;
pos += len;
if (narg != args.Length)
throw new System.ArgumentException("incorrect # of arguments for format string");
// second pass
// print each argument separately
var result = new StringBuilder(total_len);
var part = new StringBuilder(maxlen + 1); // include terminating zero
pos = 0; narg = 1;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
call_snprintf(ref part, part.Capacity, fs, args[narg++]);
result.Append(part);
Console.WriteLine(part);
else // copy literal part as is
result.Append(fmt, pos, len);
pos += len;
return result.ToString();
// C# have no vararg templates, as C++03, also max size of tuple limited to 8 elements,
// also impossible to create empty tuple, so maximum number arguments limited to 7 (plus format string as 0-th element).
static public string format<T1, T2, T3, T4, T5, T6, T7>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6, a7));
static public string format<T1, T2, T3, T4, T5, T6>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6));
static public string format<T1, T2, T3, T4, T5>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5));
static public string format<T1, T2, T3, T4>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4)
return format(Tuple.Create(fmt, a1, a2, a3, a4));
static public string format<T1, T2, T3>(string fmt, T1 a1, T2 a2, T3 a3)
return format(Tuple.Create(fmt, a1, a2, a3));
static public string format<T1, T2>(string fmt, T1 a1, T2 a2)
return format(Tuple.Create(fmt, a1, a2));
static public string format<T1>(string fmt, T1 a1)
return format(Tuple.Create(fmt, a1));
static public string format(string fmt)
return format(Tuple.Create(fmt));
;
public class Program
unsafe public static void Main()
// System.Threading.Thread.Sleep(100000);
int z = 123;
int* y = &z;
IntPtr v = (IntPtr)y;
string s = FK0.Format.format("%p %d %d", v, *y, z);
Console.WriteLine(s);
c# .net printf clr coreclr
4
Is there a particular reason you want to use this rather than the existing C# capabilities likestring.Format?
– mjwills
Nov 9 at 11:49
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with astring.Formatcall as @mjwills said, you can always create apublic class Tuple<T1, T2, ....., T25>if you want. It won't solve the problem, though
– Camilo Terevinto
Nov 9 at 11:58
1
There's also a (undocumented?) keyword called__arglistwhich can be used to call varargs functions likeprintf. But I would recommend sticking toString.Formatfor code that's in a production environment.
– Dirk
Nov 9 at 12:04
1
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49
|
show 8 more comments
up vote
-2
down vote
favorite
up vote
-2
down vote
favorite
I want to write function for C#, which will be similar to sprintf(3) and vsnprintf(3) functions in C (or similar to "format" command in Tcl). Currently I have some success with it, but still have a few questions.
Below is the source code. Class "Format" contains few public functions, which accepts variable arguments list (but no more than 7 arguments, see below) and produce formatted string. This is analog of sprintf(3) function. Also function "format" may accept C# tuple, which should hold format string in first element, and arguments for format string in other elements -- this is analog of vsprintf(3) function.
Unfortunately, here I have two major limitations:
1) I can't pass more than seven arguments to format() function, because arguments passed in C# tuple, and tuple can't have more than eight elements (first element is format string itself, this is needed because empty tuples unavailable in C#). I hope to obtain some suggestions, how can I improve my format() function to avoid this limitation.
2) Another major limitation, that not all types can be passed to C# template. Especially, I can't pass pointers to format function (in this case I will got following error: "error CS0306: The type 'int*' may not be used as a type argument"). This is C# limitation? It's possible to rewrite format() function(s) to avoid this limitation?
Another major inconvenience, is that I should open some particular library name, and use C function name, which is different for different operation systems:
for windows I should use "msvcrt.dll" and "_snprintf";
for linux I should use "libc.so.6" and "snprintf";
for linux on embedded platform C-library name might have different name...
It's possible to define which library should be opened at runtime, or extern functions marshalling might be determined only at compile time? So, I see two variants possible here:
1) I need produce different DLL's for different target platforms;
2) Or I can decide at runtime, which function name and libc-library should be used?
I not understood, how can I rewrite the code for first or second variant. Also it looks very inconvenient to have knowledge about libc name. Why just not call dlsym("snprintf") ?
Another question, I trying limit using of dynamic memory, but looks It's impossible to avoid allocating few String and StringBuilder classes on heap. This is looking scary, because when programming on C/C++ it's possible to do almost all work without dynamic memory allocation. May be somebody suggests me, how to improve format() functions to avoid dynamic memory allocation.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace FK0
using Args = ITuple;
public class Format
// const string LIBC = "msvcrt.dll"; //"libc.so";
// const string FUNC = "_snprintf";
const string LIBC = "libc.so.6";
const string FUNC = "snprintf";
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I4)] int a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I8)] long a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, double a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.LPStr)]string a1);
// function returns length of next format segment (string, copied as is, or single format spec.)
static private int parse_format(string fmt, int pos)
int p = fmt.IndexOf('%', pos);
if (p == -1) return fmt.Length - pos; // copy to end of string
else if (p != pos) return p - pos; // copy till %
char fmt_term = 'd','i','o','u','x','X','e','E','f','F','g','G','a','A','c','s','p','n','%' ;
int e = fmt.IndexOfAny(fmt_term, p + 1);
if (e == -1) throw new System.ArgumentException("invalid format string");
return e - p + 1; // format specifier length
// call real `snprintf(3)' from C-library, marshal arguments appropriately
static private int call_snprintf(ref StringBuilder res, int len, StringBuilder fmt, Object arg)
arg is IntPtr) // XXX can't pass pointer to template!!!
return snprintf(res, (IntPtr)len, fmt, ((IntPtr)arg).ToInt64());
//else if (arg.GetType()
else
return snprintf(res, (IntPtr)len, fmt, Convert.ToInt32(arg));
// vsnprintf-like function (accepts all arguments in tuple)
static public string format(Args args)
if (! (args[0] is string)) // check, that first argument is string
throw new System.ArgumentException("wrong string format type");
// first pass
// compute number of arguments, size of output string and max size of formatted output
string fmt = args[0].ToString();
StringBuilder ns = null, fs = new StringBuilder();
int total_len = 0, maxlen = 0, narg = 1;
int pos = 0;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
int flen = call_snprintf(ref ns, 0, fs, args[narg]);
if (flen == -1) throw new System.ArgumentException("wrong format string");
total_len += flen;
if (flen > maxlen) maxlen = flen;
narg++;
else // compute size of literal part
total_len += len;
pos += len;
if (narg != args.Length)
throw new System.ArgumentException("incorrect # of arguments for format string");
// second pass
// print each argument separately
var result = new StringBuilder(total_len);
var part = new StringBuilder(maxlen + 1); // include terminating zero
pos = 0; narg = 1;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
call_snprintf(ref part, part.Capacity, fs, args[narg++]);
result.Append(part);
Console.WriteLine(part);
else // copy literal part as is
result.Append(fmt, pos, len);
pos += len;
return result.ToString();
// C# have no vararg templates, as C++03, also max size of tuple limited to 8 elements,
// also impossible to create empty tuple, so maximum number arguments limited to 7 (plus format string as 0-th element).
static public string format<T1, T2, T3, T4, T5, T6, T7>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6, a7));
static public string format<T1, T2, T3, T4, T5, T6>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6));
static public string format<T1, T2, T3, T4, T5>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5));
static public string format<T1, T2, T3, T4>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4)
return format(Tuple.Create(fmt, a1, a2, a3, a4));
static public string format<T1, T2, T3>(string fmt, T1 a1, T2 a2, T3 a3)
return format(Tuple.Create(fmt, a1, a2, a3));
static public string format<T1, T2>(string fmt, T1 a1, T2 a2)
return format(Tuple.Create(fmt, a1, a2));
static public string format<T1>(string fmt, T1 a1)
return format(Tuple.Create(fmt, a1));
static public string format(string fmt)
return format(Tuple.Create(fmt));
;
public class Program
unsafe public static void Main()
// System.Threading.Thread.Sleep(100000);
int z = 123;
int* y = &z;
IntPtr v = (IntPtr)y;
string s = FK0.Format.format("%p %d %d", v, *y, z);
Console.WriteLine(s);
c# .net printf clr coreclr
I want to write function for C#, which will be similar to sprintf(3) and vsnprintf(3) functions in C (or similar to "format" command in Tcl). Currently I have some success with it, but still have a few questions.
Below is the source code. Class "Format" contains few public functions, which accepts variable arguments list (but no more than 7 arguments, see below) and produce formatted string. This is analog of sprintf(3) function. Also function "format" may accept C# tuple, which should hold format string in first element, and arguments for format string in other elements -- this is analog of vsprintf(3) function.
Unfortunately, here I have two major limitations:
1) I can't pass more than seven arguments to format() function, because arguments passed in C# tuple, and tuple can't have more than eight elements (first element is format string itself, this is needed because empty tuples unavailable in C#). I hope to obtain some suggestions, how can I improve my format() function to avoid this limitation.
2) Another major limitation, that not all types can be passed to C# template. Especially, I can't pass pointers to format function (in this case I will got following error: "error CS0306: The type 'int*' may not be used as a type argument"). This is C# limitation? It's possible to rewrite format() function(s) to avoid this limitation?
Another major inconvenience, is that I should open some particular library name, and use C function name, which is different for different operation systems:
for windows I should use "msvcrt.dll" and "_snprintf";
for linux I should use "libc.so.6" and "snprintf";
for linux on embedded platform C-library name might have different name...
It's possible to define which library should be opened at runtime, or extern functions marshalling might be determined only at compile time? So, I see two variants possible here:
1) I need produce different DLL's for different target platforms;
2) Or I can decide at runtime, which function name and libc-library should be used?
I not understood, how can I rewrite the code for first or second variant. Also it looks very inconvenient to have knowledge about libc name. Why just not call dlsym("snprintf") ?
Another question, I trying limit using of dynamic memory, but looks It's impossible to avoid allocating few String and StringBuilder classes on heap. This is looking scary, because when programming on C/C++ it's possible to do almost all work without dynamic memory allocation. May be somebody suggests me, how to improve format() functions to avoid dynamic memory allocation.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace FK0
using Args = ITuple;
public class Format
// const string LIBC = "msvcrt.dll"; //"libc.so";
// const string FUNC = "_snprintf";
const string LIBC = "libc.so.6";
const string FUNC = "snprintf";
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I4)] int a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.I8)] long a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, double a1);
[DllImport(LIBC, EntryPoint=FUNC)] static private extern int snprintf(StringBuilder result, [MarshalAs(UnmanagedType.SysInt)] IntPtr size, StringBuilder format, [MarshalAs(UnmanagedType.LPStr)]string a1);
// function returns length of next format segment (string, copied as is, or single format spec.)
static private int parse_format(string fmt, int pos)
int p = fmt.IndexOf('%', pos);
if (p == -1) return fmt.Length - pos; // copy to end of string
else if (p != pos) return p - pos; // copy till %
char fmt_term = 'd','i','o','u','x','X','e','E','f','F','g','G','a','A','c','s','p','n','%' ;
int e = fmt.IndexOfAny(fmt_term, p + 1);
if (e == -1) throw new System.ArgumentException("invalid format string");
return e - p + 1; // format specifier length
// call real `snprintf(3)' from C-library, marshal arguments appropriately
static private int call_snprintf(ref StringBuilder res, int len, StringBuilder fmt, Object arg)
arg is IntPtr) // XXX can't pass pointer to template!!!
return snprintf(res, (IntPtr)len, fmt, ((IntPtr)arg).ToInt64());
//else if (arg.GetType()
else
return snprintf(res, (IntPtr)len, fmt, Convert.ToInt32(arg));
// vsnprintf-like function (accepts all arguments in tuple)
static public string format(Args args)
if (! (args[0] is string)) // check, that first argument is string
throw new System.ArgumentException("wrong string format type");
// first pass
// compute number of arguments, size of output string and max size of formatted output
string fmt = args[0].ToString();
StringBuilder ns = null, fs = new StringBuilder();
int total_len = 0, maxlen = 0, narg = 1;
int pos = 0;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
int flen = call_snprintf(ref ns, 0, fs, args[narg]);
if (flen == -1) throw new System.ArgumentException("wrong format string");
total_len += flen;
if (flen > maxlen) maxlen = flen;
narg++;
else // compute size of literal part
total_len += len;
pos += len;
if (narg != args.Length)
throw new System.ArgumentException("incorrect # of arguments for format string");
// second pass
// print each argument separately
var result = new StringBuilder(total_len);
var part = new StringBuilder(maxlen + 1); // include terminating zero
pos = 0; narg = 1;
while (pos < fmt.Length)
int len = parse_format(fmt, pos);
if (fmt[pos] == '%') // pass format specifier to snprintf(3)
fs.Clear(); fs.Append(fmt, pos, len);
call_snprintf(ref part, part.Capacity, fs, args[narg++]);
result.Append(part);
Console.WriteLine(part);
else // copy literal part as is
result.Append(fmt, pos, len);
pos += len;
return result.ToString();
// C# have no vararg templates, as C++03, also max size of tuple limited to 8 elements,
// also impossible to create empty tuple, so maximum number arguments limited to 7 (plus format string as 0-th element).
static public string format<T1, T2, T3, T4, T5, T6, T7>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6, a7));
static public string format<T1, T2, T3, T4, T5, T6>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5, a6));
static public string format<T1, T2, T3, T4, T5>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
return format(Tuple.Create(fmt, a1, a2, a3, a4, a5));
static public string format<T1, T2, T3, T4>(string fmt, T1 a1, T2 a2, T3 a3, T4 a4)
return format(Tuple.Create(fmt, a1, a2, a3, a4));
static public string format<T1, T2, T3>(string fmt, T1 a1, T2 a2, T3 a3)
return format(Tuple.Create(fmt, a1, a2, a3));
static public string format<T1, T2>(string fmt, T1 a1, T2 a2)
return format(Tuple.Create(fmt, a1, a2));
static public string format<T1>(string fmt, T1 a1)
return format(Tuple.Create(fmt, a1));
static public string format(string fmt)
return format(Tuple.Create(fmt));
;
public class Program
unsafe public static void Main()
// System.Threading.Thread.Sleep(100000);
int z = 123;
int* y = &z;
IntPtr v = (IntPtr)y;
string s = FK0.Format.format("%p %d %d", v, *y, z);
Console.WriteLine(s);
c# .net printf clr coreclr
c# .net printf clr coreclr
asked Nov 9 at 11:48
fk0
566
566
4
Is there a particular reason you want to use this rather than the existing C# capabilities likestring.Format?
– mjwills
Nov 9 at 11:49
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with astring.Formatcall as @mjwills said, you can always create apublic class Tuple<T1, T2, ....., T25>if you want. It won't solve the problem, though
– Camilo Terevinto
Nov 9 at 11:58
1
There's also a (undocumented?) keyword called__arglistwhich can be used to call varargs functions likeprintf. But I would recommend sticking toString.Formatfor code that's in a production environment.
– Dirk
Nov 9 at 12:04
1
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49
|
show 8 more comments
4
Is there a particular reason you want to use this rather than the existing C# capabilities likestring.Format?
– mjwills
Nov 9 at 11:49
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with astring.Formatcall as @mjwills said, you can always create apublic class Tuple<T1, T2, ....., T25>if you want. It won't solve the problem, though
– Camilo Terevinto
Nov 9 at 11:58
1
There's also a (undocumented?) keyword called__arglistwhich can be used to call varargs functions likeprintf. But I would recommend sticking toString.Formatfor code that's in a production environment.
– Dirk
Nov 9 at 12:04
1
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49
4
4
Is there a particular reason you want to use this rather than the existing C# capabilities like
string.Format?– mjwills
Nov 9 at 11:49
Is there a particular reason you want to use this rather than the existing C# capabilities like
string.Format?– mjwills
Nov 9 at 11:49
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with a
string.Format call as @mjwills said, you can always create a public class Tuple<T1, T2, ....., T25> if you want. It won't solve the problem, though– Camilo Terevinto
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with a
string.Format call as @mjwills said, you can always create a public class Tuple<T1, T2, ....., T25> if you want. It won't solve the problem, though– Camilo Terevinto
Nov 9 at 11:58
1
1
There's also a (undocumented?) keyword called
__arglist which can be used to call varargs functions like printf. But I would recommend sticking to String.Format for code that's in a production environment.– Dirk
Nov 9 at 12:04
There's also a (undocumented?) keyword called
__arglist which can be used to call varargs functions like printf. But I would recommend sticking to String.Format for code that's in a production environment.– Dirk
Nov 9 at 12:04
1
1
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49
|
show 8 more comments
1 Answer
1
active
oldest
votes
up vote
1
down vote
Using the C# params parameter modifier, you can have the arguments to a method passed as an array:
public static string format(string format, params object args)
var n = 0;
return String.Format(format.Replace(new Regex(@"%[+-0-9.]*[a-z]"), m => $"n++"), args);
Now you can call it like:
Console.WriteLine(Format.format("test: %s %x", "this", 23));
Of course, this version of format just dumps all arguments in their default format, you would need to process each format specifier in a real implementation.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Using the C# params parameter modifier, you can have the arguments to a method passed as an array:
public static string format(string format, params object args)
var n = 0;
return String.Format(format.Replace(new Regex(@"%[+-0-9.]*[a-z]"), m => $"n++"), args);
Now you can call it like:
Console.WriteLine(Format.format("test: %s %x", "this", 23));
Of course, this version of format just dumps all arguments in their default format, you would need to process each format specifier in a real implementation.
add a comment |
up vote
1
down vote
Using the C# params parameter modifier, you can have the arguments to a method passed as an array:
public static string format(string format, params object args)
var n = 0;
return String.Format(format.Replace(new Regex(@"%[+-0-9.]*[a-z]"), m => $"n++"), args);
Now you can call it like:
Console.WriteLine(Format.format("test: %s %x", "this", 23));
Of course, this version of format just dumps all arguments in their default format, you would need to process each format specifier in a real implementation.
add a comment |
up vote
1
down vote
up vote
1
down vote
Using the C# params parameter modifier, you can have the arguments to a method passed as an array:
public static string format(string format, params object args)
var n = 0;
return String.Format(format.Replace(new Regex(@"%[+-0-9.]*[a-z]"), m => $"n++"), args);
Now you can call it like:
Console.WriteLine(Format.format("test: %s %x", "this", 23));
Of course, this version of format just dumps all arguments in their default format, you would need to process each format specifier in a real implementation.
Using the C# params parameter modifier, you can have the arguments to a method passed as an array:
public static string format(string format, params object args)
var n = 0;
return String.Format(format.Replace(new Regex(@"%[+-0-9.]*[a-z]"), m => $"n++"), args);
Now you can call it like:
Console.WriteLine(Format.format("test: %s %x", "this", 23));
Of course, this version of format just dumps all arguments in their default format, you would need to process each format specifier in a real implementation.
answered Nov 9 at 21:15
NetMage
12.7k11734
12.7k11734
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53225180%2fprintf-like-function-for-c-sharp%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
4
Is there a particular reason you want to use this rather than the existing C# capabilities like
string.Format?– mjwills
Nov 9 at 11:49
Similar question: stackoverflow.com/questions/28155317/…
– fk0
Nov 9 at 11:58
Besides this huge amount of work that could be easily done with a
string.Formatcall as @mjwills said, you can always create apublic class Tuple<T1, T2, ....., T25>if you want. It won't solve the problem, though– Camilo Terevinto
Nov 9 at 11:58
1
There's also a (undocumented?) keyword called
__arglistwhich can be used to call varargs functions likeprintf. But I would recommend sticking toString.Formatfor code that's in a production environment.– Dirk
Nov 9 at 12:04
1
There are like half a dozen questions in here, and the entire enterprise seems like a bad idea in the first place; if you want to call printf, just call the C++/CLI version of printf! Can you break this out into one simple question per question where each question has a clear, specific answer?
– Eric Lippert
Nov 9 at 21:49