<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>i’m so full of ideas &#187; c++</title>
	<atom:link href="http://www.platinumball.net/blog/category/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.platinumball.net/blog</link>
	<description>blog</description>
	<lastBuildDate>Wed, 26 May 2010 17:16:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>printf() sucks</title>
		<link>http://www.platinumball.net/blog/2009/06/23/printf-sucks/</link>
		<comments>http://www.platinumball.net/blog/2009/06/23/printf-sucks/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 19:44:51 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[c++]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=196</guid>
		<description><![CDATA[I am a big fan of printf()-style debugging.  It helps you get an overview of a problem that traditional debuggers are not so good at.  So it&#8217;s a bit unexpected that I do not like printf() itself.
Why printf() sucks
printf() is optimized for a weird corner case that you almost never need.  You&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>I am a big fan of printf()-style debugging.  It helps you get an overview of a problem that traditional debuggers are not so good at.  So it&#8217;s a bit unexpected that I do not like printf() itself.<br />
<h3>Why printf() sucks</h3>
<p>printf() is optimized for a weird corner case that you almost never need.  You&#8217;ll no doubt recognize this as standard usage:
<pre>  printf("Hello, World!\n")</pre>
<p>Notice that newline character at the end. It&#8217;s a pain to type. As best as I can tell, it exists so you can do this:
<pre>
<div class="codesnip-container" >
<div class="c codesnip" style="font-family:monospace;"><a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span class="kw3">printf</span></a><span class="br0">&#40;</span><span class="st0">&quot;Starting long-running operation ...&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="co1">// long-running operation goes here</span>
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span class="kw3">printf</span></a><span class="br0">&#40;</span><span class="st0">&quot; finished.<span class="es1">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
</pre>
<p>&#8230; which causes the output from <i>both</i> printf() calls to be printed on the same line. Swell. How many times have you needed to do that? I first started programming in C in the late eighties, and my lifetime total so far is <i>zero</i>. I typed thousands of unnecessary newline characters before I finally wised up and wrote a replacement.<br />
<h3>Format strings are error-prone</h3>
<p>The most likely problem you&#8217;ll have with printf() and functions like it is a mismatch between the format string and the variables presented to it. For example:
<pre>  printf("Two strings: %s %s\n", "text");</pre>
<p>The format string calls for two strings to be printed, but you&#8217;ve only provided one. The call to printf() might work fine, crash, or print weird results, depending on what happens to be lying around on the stack. If your compiler is GCC &#8212; and it probably is, if you&#8217;re programming for any UNIX variant, including Mac OS X &#8212; there is a good workaround. Here&#8217;s my definition for echo(), my printf() replacement:
<pre>  void echo(const char* tfmt, ...) __attribute__((format(printf, 1, 2)));</pre>
<p>That weird <tt>__attribute__</tt> business is a GCC-ism that means &#8220;this function works like printf(), and here&#8217;s the argument numbers to use for the format string and the variable args, respectively.&#8221;</p>
<p>This feature doesn&#8217;t work unless you specifically enable the proper GCC warning.  If you&#8217;re using makefiles or the command line, pass <tt>-Wformat</tt> to the compiler. If you&#8217;re using Xcode, bring up the project information window. In the &#8220;Build&#8221; tab, there&#8217;s a section called &#8220;GCC 4.0 &#8211; Warnings.&#8221; The warning you want is labeled &#8220;Typecheck Calls to printf/scanf,&#8221; which should be enabled. Once you do that, then when you write code like this:
<pre>  echo("bad format: %s %s", "text");</pre>
<p>The compiler will give you this warning:
<pre>  warning: too few arguments for format</pre>
<p>&#8230; which saves you from the undefined behavior your program was about to be subjected to.</p>
<p>(C++ introduced <tt>cout</tt>, which is a printf() replacement. It handily works around the format string issue discussed here. I&#8217;ve always felt that <tt>cout</tt> introduces more problems than it solves, so I personally avoid it.)<br />
<h3>Functions you can use</h3>
<p>The sample code that follows includes three functions you might want to use in your own programs.</p>
<p><b><tt>echo()</tt></b> &#8212; works exactly the same as printf(), except it doesn&#8217;t require a newline at the end of its format string.</p>
<p><b><tt>sfmt()</tt></b> &#8212; works exactly the same as echo(), except it puts the formatted contents into a std::string object, rather than printing to stdout.</p>
<p><b><tt>fmtArg()</tt></b> &#8212; useful if you want to build your own printf()-like function similar to echo() or sfmt(). Have a look at how echo() uses it, which should be enough for you to get started.<br />
<h3>Example code</h3>
<p>First the header file, printf_sucks.h:
<pre>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;"><span class="co1">// printf_sucks.h -- printf() alternative</span>
<span class="co1">// by allen brunson &nbsp;june 18 2009</span>

<span class="co2">#ifndef PRINTF_SUCKS_H</span>
<span class="co2">#define PRINTF_SUCKS_H</span>

<span class="co1">// sfmt() and support functions</span>

std<span class="sy4">::</span><span class="me2">string</span> fmtArg<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, <span class="kw4">va_list</span> args<span class="br0">&#41;</span><span class="sy4">;</span>
std<span class="sy4">::</span><span class="me2">string</span> fmtArgLarge<span class="br0">&#40;</span>int32_t byteCount, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, <span class="kw4">va_list</span> args<span class="br0">&#41;</span><span class="sy4">;</span>
std<span class="sy4">::</span><span class="me2">string</span> sfmt<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, ...<span class="br0">&#41;</span> __attribute__<span class="br0">&#40;</span><span class="br0">&#40;</span>format<span class="br0">&#40;</span><span class="kw3">printf</span>, 1, 2<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp;
<span class="co1">// echo(), a better printf()</span>

<span class="kw4">void</span> echo<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, ...<span class="br0">&#41;</span> __attribute__<span class="br0">&#40;</span><span class="br0">&#40;</span>format<span class="br0">&#40;</span><span class="kw3">printf</span>, 1, 2<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>

<span class="co2">#endif &nbsp;// PRINTF_SUCKS_H</span></div>
</div>
</pre>
<p>Now the source file, printf_sucks.cpp:
<pre>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;"><span class="co1">// printf_sucks.cpp -- printf() alternative</span>
<span class="co1">// by allen brunson &nbsp;june 18 2009</span>

<span class="co2">#include &lt;assert.h&gt;</span>
<span class="co2">#include &lt;stdio.h&gt;</span>
<span class="co2">#include &lt;stdint.h&gt;</span>
<span class="co2">#include &lt;stdlib.h&gt;</span>
<span class="co2">#include &lt;string&gt;</span>
<span class="co2">#include &quot;printf_sucks.h&quot;</span>

<span class="kw4">void</span> echo<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, ...<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">va_list</span> &nbsp; &nbsp; &nbsp;args <span class="sy1">=</span> <span class="kw2">NULL</span><span class="sy4">;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">string</span> &nbsp;text<span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">va_start</span><span class="br0">&#40;</span>args, tfmt<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; text <span class="sy1">=</span> fmtArg<span class="br0">&#40;</span>tfmt, args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw3">va_end</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">puts</span><span class="br0">&#40;</span>text.<span class="me1">c_str</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
<span class="br0">&#125;</span>

std<span class="sy4">::</span><span class="me2">string</span> fmtArg<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, <span class="kw4">va_list</span> args<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">const</span> int32_t &nbsp;kBufferSize <span class="sy1">=</span> 2 <span class="sy2">*</span> <span class="nu0">1024</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="co1">// the extra four bytes are to guard against buffer overruns</span>
&nbsp; &nbsp; <span class="kw4">char</span> &nbsp; &nbsp; cbuf<span class="br0">&#91;</span>kBufferSize <span class="sy2">+</span> 4<span class="br0">&#93;</span><span class="sy4">;</span>
&nbsp; &nbsp; int32_t &nbsp;size <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>

&nbsp; &nbsp; <span class="kw3">assert</span><span class="br0">&#40;</span>tfmt <span class="sy3">&amp;&amp;</span> tfmt<span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy4">;</span>

&nbsp; &nbsp; size <span class="sy1">=</span> vsnprintf<span class="br0">&#40;</span>cbuf, kBufferSize, tfmt, args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>size <span class="sy1">&lt;</span> kBufferSize<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> std<span class="sy4">::</span><span class="me2">string</span><span class="br0">&#40;</span>cbuf<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> fmtArgLarge<span class="br0">&#40;</span>size, tfmt, args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span>

<span class="co1">// called when fmtArg() didn't have a big enough buffer</span>

std<span class="sy4">::</span><span class="me2">string</span> fmtArgLarge<span class="br0">&#40;</span>int32_t byteCount, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, <span class="kw4">va_list</span> args<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">char</span><span class="sy2">*</span> &nbsp; &nbsp; &nbsp; &nbsp;cbuf <span class="sy1">=</span> <span class="kw2">NULL</span><span class="sy4">;</span>
&nbsp; &nbsp; int32_t &nbsp; &nbsp; &nbsp;clen <span class="sy1">=</span> byteCount <span class="sy2">+</span> <span class="nu0">10</span><span class="sy4">;</span>
&nbsp; &nbsp; int32_t &nbsp; &nbsp; &nbsp;size <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">string</span> &nbsp;text<span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; cbuf <span class="sy1">=</span> <span class="kw2">static_cast</span><span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="kw3">malloc</span><span class="br0">&#40;</span>clen <span class="sy2">+</span> 4<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy3">!</span>cbuf<span class="br0">&#41;</span> <span class="kw1">return</span> <span class="st0">&quot;&quot;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; size <span class="sy1">=</span> vsnprintf<span class="br0">&#40;</span>cbuf, clen, tfmt, args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw3">assert</span><span class="br0">&#40;</span>size <span class="sy1">&lt;</span> clen<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; text.<span class="me1">assign</span><span class="br0">&#40;</span>cbuf<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">free</span><span class="br0">&#40;</span>cbuf<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; cbuf <span class="sy1">=</span> <span class="kw2">NULL</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> text<span class="sy4">;</span>
<span class="br0">&#125;</span>

<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">**</span> argv<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; echo<span class="br0">&#40;</span><span class="st0">&quot;hello from echo: %s %d&quot;</span>, <span class="st0">&quot;text&quot;</span>, 2<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span>
<span class="br0">&#125;</span>

<span class="co1">// works like echo(), but puts the formatted contents into a std::string</span>

std<span class="sy4">::</span><span class="me2">string</span> sfmt<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> tfmt, ...<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">va_list</span> &nbsp; &nbsp; &nbsp;args <span class="sy1">=</span> <span class="kw2">NULL</span><span class="sy4">;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">string</span> &nbsp;text<span class="sy4">;</span>

&nbsp; &nbsp; <span class="kw3">assert</span><span class="br0">&#40;</span>tfmt <span class="sy3">&amp;&amp;</span> tfmt<span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy4">;</span>

&nbsp; &nbsp; <span class="kw3">va_start</span><span class="br0">&#40;</span>args, tfmt<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; text <span class="sy1">=</span> fmtArg<span class="br0">&#40;</span>tfmt, args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw3">va_end</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> text<span class="sy4">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/06/23/printf-sucks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
