Why does semi-colon after a macro cause illegal else compile error
<p>Apparently I have a fundamental misunderstanding of how macros work.  I thought a macro just caused the preprocessor to replace the <code>@define</code>d macro with the replacement text.  But apparently that's not always the case.  My code follows:
<strong>TstBasInc.h</strong></p>

<pre><code>#pragma once

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;math.h&gt;
#include &lt;stdint.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;time.h&gt;

//  copy macro
#define Cpy(ToVar, FrmVar) do {                                                                                 \
                                errno = strncpy_s(ToVar, sizeof(ToVar), FrmVar, _TRUNCATE);                     \
                                    if (errno == STRUNCATE)                                                     \
                                        fprintf(stderr, "string '%s' was truncated to '%s'\n", FrmVar, ToVar);  \
                            } while(0);

//  clear numeric array macro
#define ClrNumArr(ArrNam, ArrCnt)           \
            for (s = 0; s &lt; ArrCnt; s++)    \
                ArrNam[s] = 0;


uint32_t    s;          //  subscript

typedef struct {
    short   C;
    short   YY;
    short   MM;
    short   DD;
} SysDat;
</code></pre>

<p><strong>TstMacCmpErr:</strong></p>

<pre><code>#include "stdafx.h"
#include "TstBasInc.h"      //  test basic include file

#define ARRCNT 3

int main()
{
    char    Cnd = 'E';      //  define to use 'else' path
    char    ToVar[7 + 1];   //  Cpy To-Variable
    int     IntArr[ARRCNT]; //  integer array

    Cpy(ToVar, "short")                     //  compiles with or without the semi-colon
    if (Cnd != 'E')
//      Cpy(ToVar, "short string");         //  won't compile:  illegal else without matching if
        Cpy(ToVar, "short string")          //  will compile
    else
        Cpy(ToVar, "extra long string");    //  compiles with or without the semi-colon
//  the following code shows how I thought the macro would expand to    
    {                                                                                   \
        errno = strncpy_s(ToVar, sizeof(ToVar), "short str", _TRUNCATE);                \
        if (errno == STRUNCATE)                                                         \
            fprintf(stderr, "string '%s' was truncated to '%s'\n", "short str", ToVar);;    \
    }

    if (Cnd == 'E') {
        ClrNumArr(IntArr, ARRCNT)               //  compiles with or without the semi-colon
            printf("intarr[0] = %d\n", IntArr[0]);
    }
    else
        printf("intarr[0] is garbage\n");

    return 0;
}
</code></pre>

<p>The results follow:</p>

<pre><code>string 'extra long string' was truncated to 'extra l'
string 'short str' was truncated to 'short s'
intarr[0] = 0;
</code></pre>

<p>As the comments say, when I have a semi-colon after <code>Cpy(ToVar, "short string");</code> it won't even compile because I get an <code>"C2181   illegal else without matching if"</code> error.  As you see, I tried adding a do-while in the macro as suggested <a href="https://stackoverflow.com/questions/154136/do-while-and-if-else-statements-in-c-c-macros">in this post</a>, but it didn't make any difference.  When the macro code is copied directly (even without the do-while) that code works okay.  I would have thought just adding the braces in the macro would have fixed the problem but it didn't.  It must have something to do with the <code>Cpy</code> ending in an <code>if</code> because the <code>ClrNumArr</code> macro compiles with or without the semi-colon.  So can someone tell me why the <code>Cpy</code> macro doesn't just replace the text?  I must be missing something simple.</p>

<p>I'm using VS 2015 Community Edition Update 1.</p>

<p>Edit:  I documented the problem and isolated it to (I think) the <code>if</code> statement in the <code>Cpy</code> macro.  <em>Still</em> nobody has explained why the macro didn't expand the way I thought it should.  That should have been the title of the post, as that's my question more than the problem with the semi-colon, which I now have a solution for.</p>