<?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>cnicholson.net &#187; while</title>
	<atom:link href="http://cnicholson.net/tag/while/feed/" rel="self" type="application/rss+xml" />
	<link>http://cnicholson.net</link>
	<description>programming is hard.</description>
	<lastBuildDate>Mon, 24 Jan 2011 02:07:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Stupid C++ Tricks: do/while(0) and C4127</title>
		<link>http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/</link>
		<comments>http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 17:33:41 +0000</pubDate>
		<dc:creator>charles</dc:creator>
				<category><![CDATA[Stupid C++ Tricks]]></category>
		<category><![CDATA[4127]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[C4127]]></category>
		<category><![CDATA[do]]></category>
		<category><![CDATA[while]]></category>

		<guid isPermaLink="false">http://cnicholson.net/?p=123</guid>
		<description><![CDATA[A nice little quickie:  I briefly discuss in my assert ramblings why it&#8217;s important to wrap all of your multi-line macros in do/while(0) blocks.  An unfortunate side-effect of this is that the construction // NOISY CODE #define MULTI_LINE_MACRO \ do { \ std::printf("Hello "); \ std::printf("world!\n"); \ } while (0) will trigger C4127: &#8220;Conditional expression [...]]]></description>
			<content:encoded><![CDATA[<p>A nice little quickie:  I briefly discuss in my <a href="http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/">assert ramblings</a> why it&#8217;s important to wrap all of your multi-line macros in <a href="http://kernelnewbies.org/FAQ/DoWhile0">do/while(0) blocks</a>.  An unfortunate side-effect of this is that the construction</p>
<pre name="code" class="c++:nocontrols">
// NOISY CODE
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
	} while (0)
</pre>
<p>will trigger C4127: &#8220;Conditional expression is constant&#8221; in Visual Studio 2003/2005, and probably 2008 as well (but I haven&#8217;t tried it).  The culprit is the &#8220;while(0)&#8221; part, the compiler thinks we&#8217;re making a mistake when of course this is all very intentional.  Let&#8217;s see what we can do to fix it!<br />
<span id="more-123"></span></p>
<p>This is really unfortunate because these macros live in header files, and for the life of me I couldn&#8217;t figure out a way to shut up that warning!  The best way I&#8217;d found to deal with it was simply to issue a sledgehammer #pragma &#8220;shut the hell up&#8221; directive:</p>
<pre name="code" class="c++:nocontrols">
// QUIET BUT RUDE CODE
#pragma warning(disable:4127)
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
	} while (0)
</pre>
<p>This is very bad.  I don&#8217;t want to globally silence 4127, just only for my multi-line macro stuff, but now every cpp file that #includes my header file has 4127 forever silenced!  This is inconvenient enough inside your own codebase, but it&#8217;s flat-out rude if you&#8217;re writing middleware!  I&#8217;ve used middleware that changes the warning levels on my cpp files, and it was an unpleasant surprise to find that the warnings I was expecting to receive were being muted before the compiler ever saw any of my code!</p>
<p>What we really want to do is something like this:</p>
<pre name="code" class="c++:nocontrols">
// BROKEN CODE
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
#pragma warning(push)
#pragma warning(disable:4127)
	} while (0)
#pragma warning(pop)
</pre>
<p>This preserves the global warning state, but still disables 4127 for the duration of our intentional violation.  Unfortunately though, since the preprocessor isn&#8217;t recursive, that&#8217;s illegal.  We can&#8217;t put #pragma directives inside macro definitions!  We can also try doing something like this:</p>
<pre name="code" class="c++:nocontrols">
// STUPID CODE
#pragma warning(push)
#pragma warning(disable:4127)
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
	} while (0)
#pragma warning(pop)
</pre>
<p>But that doesn&#8217;t do what we want at all, because of course the #pragmas don&#8217;t wrap the macro at its invocation site, and wrapping the definition doesn&#8217;t do anything!</p>
<p>Well, it turns out that Microsoft implemented the <a href="http://msdn.microsoft.com/en-us/library/d9x1s805.aspx">__pragma</a> directive for just this purpose.  Using __pragma instead of #pragma lets you embed pragma directives inside of macros!  This turns out to be just what the doctor ordered.  We can now throw together multi-line macro wrappers that emit no warnings on /W4 and don&#8217;t change the global warning state!</p>
<pre name="code" class="c++:nocontrols">
// WORKING CODE
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
	} while (0) \
__pragma(warning(pop))
</pre>
<p>We can now generalize this approach to a set of helper macros that help you always correctly implement multi-line macros:</p>
<pre name="code" class="c++">
#define MULTI_LINE_MACRO_BEGIN do {
#define MULTI_LINE_MACRO_END \
	__pragma(warning(push)) \
	__pragma(warning(disable:4127)) \
	} while(0) \
	__pragma(warning(pop))
</pre>
<p>And here&#8217;s our original example reimplemented:</p>
<pre name="code" class="c++:nocontrols">
#define MULTI_LINE_MACRO \
	MULTI_LINE_MACRO_BEGIN \
		std::printf("Hello "); \
		std::printf("world!\n"); \
	MULTI_LINE_MACRO_END
</pre>
<p>Finally, I should point out that both a coworker of mine and <a href="http://lists.boost.org/Archives/boost/2004/09/72487.php">someone on the boost mailing list</a> have found another slightly bizarre workaround to this problem:  For some reason, the code</p>
<pre name="code" class="c++:nocontrols">
// WORKING CODE, BUT A LITTLE SCARY
#define MULTI_LINE_MACRO \
	do { \
		std::printf("Hello "); \
		std::printf("world!\n"); \
	} while (__LINE__ == -1)
</pre>
<p> <br />
doesn&#8217;t trigger C4127.  I can only conclude that it&#8217;s unintended compiler behavior, because replacing __LINE__ with a literal integer causes it to trigger, and I can&#8217;t imagine that MS intended that code to be the correct way to dodge 4127.  Use it at your own peril, and don&#8217;t be surprised if a new version of Visual Studio or some random service pack breaks it!</p>
]]></content:encoded>
			<wfw:commentRss>http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

