<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0' xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Veasna Chhaysy-Park</title>
    <description>Engine and graphics programmer (and other tidbits too)</description>
    <link>https://veasna.silvrback.com/feed</link>
    <atom:link href="https://veasna.silvrback.com/feed" rel="self" type="application/rss+xml"/>
    <category domain="veasna.silvrback.com">Content Management/Blog</category>
    <language>en-us</language>
      <pubDate>Sat, 01 Mar 2014 16:12:27 -0800</pubDate>
    <managingEditor>luckay52@hotmail.com (Veasna Chhaysy-Park)</managingEditor>
      <item>
        <guid>https://veasna.silvrback.com/if-vs-ifdef#2045</guid>
          <pubDate>Sat, 01 Mar 2014 16:12:27 -0800</pubDate>
        <link>https://veasna.silvrback.com/if-vs-ifdef</link>
        <title>#if vs #ifdef</title>
        <description>feat. #elif &amp; defined</description>
        <content:encoded><![CDATA[<p>I&#39;ve always been interested in cross-platform development for some time now and so I&#39;m trying to tackle it head first. This means tough times ahead and many hours will be spent scouring obscure posts and forums, but hopefully I&#39;ll be able to come out of it having improved as a programmer and obtaining some valuable skills.</p>

<p>One of the necessary things I&#39;ve had to use are #ifdef statements to separate platform specific code and this led to me to investigate a little further about how they work. The basic way that they work is that if the condition is met, the compiler will compile the code inside the statement. Otherwise, it will ignore the code within the statement as if it weren&#39;t there. This is very handy when you want to call a function specific to Windows, but not on OS X or Linux. You can also do things like have debug print statements exist only in debug mode, without having to comment them in and out to toggle them on and off. </p>

<p>One of the most common usages is the #ifdef statment, which checks if a symbol is defined. I&#39;ve been doing a little research on other commands such as #ifndef, #if, and so on and started learning the little nuances between them. Here are some of the things I&#39;ve found.</p>

<p>Let&#39;s say I&#39;m using Visual Studio on Windows and I&#39;ve already made the preprocessor  define the symbol &#39;WINDOWS&#39;in the project settings.</p>
<div class="highlight"><pre><span></span><span class="cp">#ifdef WINDOWS</span>
  <span class="c1">//This code compiles just fine if WINDOWS is defined</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>

<span class="cp">#if WINDOWS</span>
 <span class="c1">//This will work as well</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>Pretty simple and it works. You could use #ifdef  or plain #if in this situation, but there is a difference between the two! Let&#39;s define the symbol &#39;WINDOWS&#39; ourselves:</p>
<div class="highlight"><pre><span></span><span class="cp">#define WINDOWS</span>

<span class="cp">#ifdef WINDOWS</span>
  <span class="c1">//Works just fine</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>

<span class="cp">#if WINDOWS</span>
 <span class="c1">//Error: expected an expression</span>
 <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>Uh-oh. That didn&#39;t work and the compiler is complaining. So what changed? In Visual Studio, when you set a preprocessor value, it will automatically do something like:</p>
<div class="highlight"><pre><span></span><span class="cp">#define WINDOWS 1</span>
</pre></div>
<p>Where the symbol is assigned a value of 1. Let&#39;s do the same for ours.</p>
<div class="highlight"><pre><span></span><span class="cp">#define WINDOWS 1</span>

<span class="cp">#ifdef WINDOWS</span>
   <span class="c1">//Works just fine</span>
   <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>

<span class="cp">#if WINDOWS</span>
  <span class="c1">//Now it works</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>Now let&#39;s try another value, like 0</p>
<div class="highlight"><pre><span></span><span class="cp">#define WINDOWS 0</span>

<span class="cp">#ifdef WINDOWS</span>
  <span class="c1">//Works just fine</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>

<span class="cp">#if WINDOWS </span>
  <span class="c1">//Is ignored and does not compile!</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>So what is the difference? The #ifdef will check if the symbol <strong>exists</strong>,whereas #if checks the <strong>value</strong> [1].</p>

<p>So is there a potential pitfall for this? Perhaps. (Although I&#39;m not sure how many people define a value to 0 <em>and</em> use #if).</p>

<p>Let&#39;s take another example:</p>
<div class="highlight"><pre><span></span><span class="cp">#define LINUX 1</span>

<span class="cp">#ifdef WINDOWS</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#elif LINUX</span>
  <span class="c1">//Linux must be defined and and has a value that hopefully isn&#39;t 0...</span>
  <span class="n">DoLinuxStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>It will work for the most part and most likely won&#39;t run into any issues, although it isn&#39;t entirely fool proof. Luckily for those of us who are picky, we have the <em>&#39;defined&#39;</em> keyword that we can use. So let&#39;s modify the last statement to:</p>
<div class="highlight"><pre><span></span><span class="cp">#define LINUX</span>

<span class="cp">#ifdef WINDOWS</span>
  <span class="c1">//Ok</span>
  <span class="n">DoWindowsStuff</span><span class="p">();</span>
<span class="cp">#elif defined LINUX</span>
  <span class="c1">//Ok, only checks if LINUX is simply defined</span>
  <span class="n">DoLinuxStuff</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>It is a bit more wordy, although there is some flexibility that comes with using the <em>&#39;defined&#39;</em> keyword [2]. You can do stuff like:</p>
<div class="highlight"><pre><span></span><span class="cp">#if defined WINDOWS &amp;&amp; defined MAC</span>
  <span class="n">ClosedFunction</span><span class="p">();</span>
<span class="cp">#elif defined LINUX || defined STEAMOS</span>
  <span class="n">OpenFunction</span><span class="p">();</span>
<span class="cp">#endif</span>
</pre></div>
<p>Something I&#39;ve read as good practice from the Steam Dev Days from Ryan C. Gordon (Icculus) is to include an else statement [3]. This is useful in the case you are developing for another platform but forget to call a specific function that each platform has to call, like say creating an OpenGL context or DirectX device.</p>
<div class="highlight"><pre><span></span><span class="cp">#if defined WINDOWS</span>
  <span class="c1">//Windows</span>
<span class="cp">#elif defined MAC_OS_X</span>
  <span class="c1">//Mac OS X</span>
<span class="cp">#elif defined LINUX</span>
  <span class="c1">//Linux</span>
<span class="cp">#elif defined APPLE_IOS</span>
 <span class="c1">//iOS</span>
<span class="cp">#else</span>
<span class="cp">#error New unsupported platform detected!</span>
<span class="cp">#endif</span>
</pre></div>
<p>This way, if you move on to a new platform, the compiler will tell you all the spots where you have platform dependent code or where you have yet to integrate dependent areas for that particular platform. For instance, in my own engine, printf works fine in terms logging output to a console for most platforms, except for android. In my code, I have:</p>
<div class="highlight"><pre><span></span><span class="kt">void</span> <span class="nf">log_message</span><span class="p">(</span> <span class="p">...</span> <span class="p">)</span>
<span class="p">{</span>
<span class="cp">#if defined WINDOWS || defined MAC_OS_X  || defined LINUX || defined APPLE_IOS</span>
  <span class="n">printf</span><span class="p">(</span> <span class="p">...);</span>
<span class="cp">#elif defined ANDROID</span>
  <span class="n">__android_log_print</span><span class="p">(...);</span>
<span class="cp">#else</span>
<span class="cp">#error Console logging not integrated on this platform</span>
<span class="cp">#endif</span>
<span class="p">}</span>
</pre></div>
<p>This made it useful to separate out a version specific to android, and now if I develop on to another platform, the compiler will tell me I have yet to test message logging on it. It also means I now know that can&#39;t assume printf will just output to a console on some platforms.</p>

<p>And there you have it. Hopefully this will help you out in cross platform development!</p>

<hr>

<p><strong>References:</strong></p>

<p>[1] <a href="http://stackoverflow.com/questions/3802988/difference-between-preprocessor-directives-if-and-ifdef">http://stackoverflow.com/questions/3802988/difference-between-preprocessor-directives-if-and-ifdef</a></p>

<p>[2] <a href="http://stackoverflow.com/questions/1714245/difference-between-if-definedwin32-and-ifdefwin32">http://stackoverflow.com/questions/1714245/difference-between-if-definedwin32-and-ifdefwin32</a></p>

<p>[3] Gordon, &quot;Getting Started with Linux Game Development&quot;,<br>
<a href="http://media.steampowered.com/apps/steamdevdays/slides/gettingstartedwithlinux.pdf">http://media.steampowered.com/apps/steamdevdays/slides/gettingstartedwithlinux.pdf</a></p>

<p>[4] <a href="http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V40F_HTML/AQTLTBTE/DOCU_078.HTM">http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V40F_HTML/AQTLTBTE/DOCU_078.HTM</a></p>
]]></content:encoded>
      </item>
  </channel>
</rss>