Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / C#

A printf implementation in C#

Rate me:
Please Sign up or sign in to vote.
4.41/5 (49 votes)
10 Feb 2015MIT3 min read 149.8K   2.4K   62   24
This article describes an implementation of printf using C#.

Screenshot - printf.jpg

Introduction

While working on a project porting a large C/C++ Unix application into the .NET world, the language requirements changed from mixed C#/VB.NET/Managed C++ to C# (and only C#). In the C/C++ sources of this project, there were many [sf]printf statements. Migrating these to the corresponding C# String.Format format is not only annoying, but also a little problematic. This is because String.Format does not support all the required possibilities, as printf does. So, what to do? The solution was to implement a printf equivalent in C#, and that's what I will present to you in this article.

Using the code

Place a reference to the Tools assembly of the demo project, or incorporate my code into your source. Call Tools.printf with the appropriate parameters, and you are done. printf features a lot of conversion and formatting options -- far more than String.Format does -- but this comes at the price that it's also more complex, in case you have never used printf. To find out more about printf and its possibilities, have a look at the printf man page or just Google for man printf.

It is important to note that not all possible printf options, conversions, and formats are supported at the moment. There is also more than one printf implementation available on the 'net! This implementation supports the most common options. It supports the l and h length modifiers, all flags such as #+- ', and the following formats: iudxXfFeEgGon. There is no difference between ASCII and Unicode strings and characters; they are always Unicode.

printf outputs to the console. It also has variations like sprinf, which returns a formatted string, and fprinf, which writes formatted output to a stream. It supports variable length parameters. If there are more format placeholders than actual value parameters, then placeholders without a value will be removed from the result.

C#
// Ouput: Account balance:       +12.345.678,00 (great)

Tools.printf("Account balance: %'+20.2f (%s)\n", 12345678, "great");

Building and testing the demo project

The demo project uses NUnit with test cases to test some printf features, but not all combinations of these. So, you will need NUnit installed.

Points of interest

Converting C/C++ code with lots of [sf]printf statements into C# is now a little easier. This printf implementation uses Regex \%([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%]) to parse the format string and uses String.Format internally wherever possible. Strings are processed by hand only if not otherwise possible, so the code is quite simple and small.

Some people have pointed out that it is possible to use either the underlying unmanaged Windows API functions like:

C#
[DllImport("msvcrt.dll",  SetLastError = false, 
  CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int sprintf(StringBuilder buff, string format, __arglist);
...
StringBuilder sb = new StringBuilder(256);
DateTime dt = DateTime.Now;
int hr = dt.Hour;
int mn = dt.Minute;
int sc = dt.Second;
int ml = dt.Millisecond;
MSVCRT.sprintf(sb, "%02i:%02i:%02i.%03i", __arglist(hr, mn, sc, ml));
string s = sb.ToString();
...

or a managed C++ wrapper called from C#:

C++
namespace FormatHelper
{
    void FormatHelper::FormatDouble(String ^%sResult, String ^sFormat, double fVal)
    {
        CString sStr;
        sStr.Format (CString(sFormat), fVal);
        sResult = gcnew String(sStr);
    }
}

Call it like this from C#:

C#
using FormatHelper;

string s = string.Empty;
Class1.FormatDouble(ref s, "%f6.1",132.459);

Both solutions will work, but sometimes it's not possible to use unmanaged code and other languages because of various reasons (Management - you know? ;-). That's because this is a complete rewrite of printf in C# without any dependencies.

Update

Thanks to Rainer Helbing, this printf implementation now also supports parameter indices in the form of "%[parameterIndex][flags][width][.precision][length]type". A detailed description can be found here.

The NUnit test routines are also modified to work as expected with all Country settings for decimal and group separators.

A bug when specifying a precision with hex format was solved.

History

  • 2007.06.14 -- First release.
  • 2009.01.26 -- Update.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Architect
Austria Austria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalexcellent! Pin
Southmountain9-May-17 15:21
Southmountain9-May-17 15:21 
Generalcongrats Pin
AndrzejBluzka23-Nov-16 7:15
AndrzejBluzka23-Nov-16 7:15 
GeneralMy vote of 5 Pin
Andy Roberts18-Oct-16 10:56
Andy Roberts18-Oct-16 10:56 
QuestionI have a hosted JavaScript emulator in .Net...wanted to offer printf style formatting ala node js... Pin
Eric Swann18-Feb-15 9:48
Eric Swann18-Feb-15 9:48 
Questionscanf Pin
mail-2212-Apr-12 2:03
mail-2212-Apr-12 2:03 
GeneralMy vote of 5 Pin
winxpdll8-Sep-11 20:32
winxpdll8-Sep-11 20:32 
GeneralMy vote of 5 Pin
fn567-Feb-11 4:35
fn567-Feb-11 4:35 
QuestionHow about performance? Pin
2LM8-Mar-10 21:55
2LM8-Mar-10 21:55 
GeneralA couple of bugs Pin
st144-Jun-09 16:57
st144-Jun-09 16:57 
AnswerRe: A couple of bugs [modified] Pin
danie_lidstrom30-Sep-10 4:28
danie_lidstrom30-Sep-10 4:28 
GeneralThanks, Code I can rely on. Pin
st143-May-09 2:59
st143-May-09 2:59 
GeneralAlthough... Pin
bobpombrio22-Apr-09 4:03
bobpombrio22-Apr-09 4:03 
AnswerRe: Although... Pin
Richard Prinz22-Apr-09 22:11
Richard Prinz22-Apr-09 22:11 
GeneralMy vote of 1 Pin
CPAV27-Jan-09 7:44
CPAV27-Jan-09 7:44 
GeneralRe: My vote of 1 Pin
Philippe Mori10-Feb-15 6:28
Philippe Mori10-Feb-15 6:28 
GeneralAlternative using MSVCRT sprintf Pin
JePo11-Dec-08 2:53
JePo11-Dec-08 2:53 
Hi Richard,

I very much enjoyed finding your arcticle on The Code Project
about a sprintf-like formatter. Being a C/C++ developer at hart I
find the format specifiers in C# confusing and lacking in possibilities.

I have to point out that when formatting an integer value of say
22 with the format specifier "%02i" the result will be "022" which
is not what I expected.

I continued looking into the possibiliy of using the msvcrt sprintf
from C# and finally I stumbled upon the following:

[DllImport("msvcrt.dll", SetLastError = false, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int sprintf(StringBuilder buff, string format, __arglist);

which one can use then in the following manner:

public static void FormatSomeNumbers()
{
StringBuilder sb = new StringBuilder(256);

DateTime dt = DateTime.Now;

int hr = dt.Hour;
int mn = dt.Minute;
int sc = dt.Second;
int ml = dt.Millisecond;

MSVCRT.sprintf(sb, "%02i:%02i:%02i.%03i", __arglist(hr, mn, sc, ml));

string s = sb.ToString();

short si = 0;
double d1 = 1;
double d2 = 2;
float f = 3;
long l = 12345;

MSVCRT.sprintf(sb, "%hi %lf %lf %f %f %I64i", __arglist(si, d1, d2, (double)f, (double)f, l));

s = sb.ToString();
}

You have to cast a float to double for this to work as
this is what sprintf seems to expect.

I thought you might find this useful.

Kind regards,

Jeroen Posch.
The Netherlands.
Questiona Bug? Pin
eminsenay5-Jun-08 1:36
eminsenay5-Jun-08 1:36 
AnswerRe: a Bug? Pin
Richard Prinz26-Jan-09 5:06
Richard Prinz26-Jan-09 5:06 
GeneralHere is an alternate solution Pin
Arthg17-Apr-08 10:55
Arthg17-Apr-08 10:55 
GeneralDubious Pin
wkempf20-Jun-07 9:46
wkempf20-Jun-07 9:46 
AnswerRe: Dubious Pin
Richard Prinz20-Jun-07 22:18
Richard Prinz20-Jun-07 22:18 
GeneralRe: Dubious Pin
wkempf21-Jun-07 2:47
wkempf21-Jun-07 2:47 
GeneralRe: Dubious Pin
Richard Prinz21-Jun-07 4:40
Richard Prinz21-Jun-07 4:40 
GeneralRe: Dubious Pin
Michael Lee Yohe25-Sep-07 5:03
Michael Lee Yohe25-Sep-07 5:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.