Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

PrintF in C# Applications

2.88/5 (7 votes)
28 Dec 2017CPOL2 min read 22.9K   14  
Compatibility DLL for porting C/C++ to C#

Introduction

This article is for programmers who port C/C++ code to C#. Porting code from C/C++ to C# can result in much effort when printf is involved, as printf has some functionality, which C# does not provide the same way. This is why I wrote the attached DLL, which allows to use printf within the .NET framework.

For a brief overview about printf, you may want to visit these pages:

Using the Code - Standard Methods

For most cases, using the static methods of the PrintFCompatibility class will do fine. It provides these static methods/properties:

  • FPrintF (for printing into a file stream)
  • PrintF (for printing into a the standard output; see also PrintfPrint property)
  • SnPrintF (for printing into a string with maximum number of characters defined)
  • SPrintF (for printing into a string)
  • PrintfPrint (for assigning the output for the PrintF function. The default is Console output, but you can change it to any other supported output, e.g. any kind of stream or into a variable).

The following code is taken from the Test program which shows the basic functionality.

C++
int length;

// Use Standard output: Console
length = CppCompatibility.PrintFormatted.PrintFCompatibility.PrintF("%f\n", 3.14159265d);

/*
length = 9
Console output:
3.1415923 and line feed.
*/


// Change standard output to stream
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
CppCompatibility.PrintFormatted.PrintFCompatibility.PrintfPrint = 
                new CppCompatibility.PrintFormatted.PrintFStream(memoryStream, 
                                                                 System.Text.Encoding.Unicode);

length = CppCompatibility.PrintFormatted.PrintFCompatibility.PrintF("%f", 3.14159265d);
memoryStream.Close();
memoryStream.Dispose();
 
/*
length = 8
Stream content:
3.1415923
*/


// Printing into a string
string formatted;
length = CppCompatibility.PrintFormatted.PrintFCompatibility.SPrintF(out formatted, "%f", 3.14159265d);

/*
length = 8
String value: 3.1415923
*/

Using the Code -  Streams

If you want to print into several streams, this could be cumbersome with the PrintFCompatibility class. Instead, you may like to use the following classes:

  • PrintFFileStream
  • PrintFStream

Each instance of the above classes can handle its own stream, which simplifies your code.

The following code is taken from the Test and shows use of the IPrintf interface and the the PrintFStream and PrintFFileStream classes:

C++
// Using PrintF classes directly: (here PrintFConsole class)
CppCompatibility.PrintFormatted.IPrintF printfConsole = 
                                         new CppCompatibility.PrintFormatted.PrintFConsole(true);
length = printfConsole.PrintF("Error Console: %20.15f\n", 3.14159265d);

/*
length = 36
Console output:
Error Console:    3.141592650000000 and line feed.
*/


// Using a file stream directly with the PrintFFileStream class
string tempFilePath = System.IO.Path.GetTempFileName();
System.IO.FileStream fileStream = new System.IO.FileStream(tempFilePath, System.IO.FileMode.OpenOrCreate);
CppCompatibility.PrintFormatted.IPrintF printfFile = 
                   new CppCompatibility.PrintFormatted.PrintFFileStream(fileStream,
                                                                        System.Text.Encoding.UTF8);

length = printfFile.PrintF("File Stream: %20.15f\n", 3.14159265d);
fileStream.Close();
fileStream.Dispose();

/*
length = 34
File content:
File Stream:    3.141592650000000 and line feed.
*/

After creating your PrintFFileStream or PrintFStream object, just use the PrintF function on that object.

If you don't want to use the above approach, you can use the following approaches with the PrintFCompatibility class:

  1. Specify the PrintfPrint object and use PrintF as shown in section "Using the Code - Standard Methods"
  2. For file streams, always specify the FileStream object with the FPrintF method of the PrintFCompatibility class.

Using the Code - Console

If you want to use Console output, you can use the PrintFConsole class. It's constructor allows to specify if you want to use the error console (specify useErrorConsole parameter to be true), or if you use the standard console (don't specify the useErrorConsole parameter or set it to false).

C++
// Error console output
bool useErrorConsole = true;
CppCompatibility.PrintFormatted.IPrintF printfFile = 
                    new CppCompatibility.PrintFormatted.PrintFConsole(useErrorConsole);
printfFile.PrintF("%20.15f\n", 3.14159265d);

// Standard console output 
useErrorConsole = false;
CppCompatibility.PrintFormatted.IPrintF printfFile = 
                    new CppCompatibility.PrintFormatted.PrintFConsole(useErrorConsole);
printfFile.PrintF("%20.15f\n", 3.14159265d);

// Standard console output
CppCompatibility.PrintFormatted.IPrintF printfFile = 
                    new CppCompatibility.PrintFormatted.PrintFConsole();
printfFile.PrintF("%20.15f\n", 3.14159265d);

The "n" Format

C/C++ defines the "n" format, which prints the numbers of characters that have been output to the point where the "n" format is specified. It expects output into an address of a signed integer variable. This results in the following dilemma:

  1. Updating an int variable in a function with C# requires to specify that variable with the ref keyword.
  2. For compatibility with C/C++ the interface specifies the params keyword for all function calls. This however makes it impossible to specify a variable with the ref keyword.

The resolution is to use the FormatInfoN class:

C++
FormatInfoN fin = new FormatInfoN();
string result;
int length = PrintFCompatibility.SPrintF(out result, "%15d%n", 13, fin);
int characterCount = fin.PrintedCharacterCount;

History

Version Number Description
0.1 Initial release
0.2 Fixed handling of plain text in format specifier.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)