开发者

What does this define statement mean?

开发者 https://www.devze.com 2022-12-10 00:24 出处:网络
I have this code to draw an ellipse in the screen but I don\'t understand what does it means the long define statement, and I only want to know how to write the same code without all that confuse defi

I have this code to draw an ellipse in the screen but I don't understand what does it means the long define statement, and I only want to know how to write the same code without all that confuse define statement.

#define incx() x++, dxt += d2xt, t += dxt 
#define incy() y--, dyt += d2yt, t += dyt

void ellipse(int xc, int yc, int rx, int ry, int color)
{
    int x = 0, y = ry;
    long rx2 = (long)rx*rx, ry2 = (long)ry*ry;
    long crit1 = -(rx2/4 + rx%2 + ry2);
    long crit2 = -(ry2/4 + ry%2 + rx2);
    long crit3 = -(ry2/4 + ry%2);
    long t = -rx2*y; // e(x+1/2,y-1/2) - (a^2+b^2)/4
    long dxt = 2*ry2*x, dyt = -2*rx2*y;
    long d2xt = 2*ry2, d2yt = 2*rx2;

    while (y>=0 && x<=rx)
    {
        pixel(xc+x, yc+y, color);
        if (x!=0 || y!=0)
            pixel(xc-x, yc-y, color);
        if (x!=0 && y!=0)
        {
            pixel(xc+x, yc-y, color);
            pixel(xc-x, yc+y, color);
        }
        if (t + ry2*x <= crit1 ||   //e(x+1,y-1/2) <= 0
     开发者_JAVA技巧       t + rx2*y <= crit3)     //e(x+1/2,y) <= 0
            incx();
        else if (t - rx2*y > crit2) //e(x+1/2,y-1) > 0
            incy();
        else
        {
            incx();
            incy();
        }
    }
}

I have tried to remove the define piece by piece and it doesn't work, any suggestion?


If you just want to remove it, run the code through cpp:

 cpp cpp.c > cppout.c

gives me

# 1 "cpp.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpp.c"



void ellipse(int xc, int yc, int rx, int ry, int color)
{
    int x = 0, y = ry;
    long rx2 = (long)rx*rx, ry2 = (long)ry*ry;
    long crit1 = -(rx2/4 + rx%2 + ry2);
    long crit2 = -(ry2/4 + ry%2 + rx2);
    long crit3 = -(ry2/4 + ry%2);
    long t = -rx2*y;
    long dxt = 2*ry2*x, dyt = -2*rx2*y;
    long d2xt = 2*ry2, d2yt = 2*rx2;

    while (y>=0 && x<=rx)
    {
        pixel(xc+x, yc+y, color);
        if (x!=0 || y!=0)
            pixel(xc-x, yc-y, color);
        if (x!=0 && y!=0)
        {
            pixel(xc+x, yc-y, color);
            pixel(xc-x, yc+y, color);
        }
        if (t + ry2*x <= crit1 ||
            t + rx2*y <= crit3)
            x++, dxt += d2xt, t += dxt;
        else if (t - rx2*y > crit2)
            y--, dyt += d2yt, t += dyt;
        else
        {
            x++, dxt += d2xt, t += dxt;
            y--, dyt += d2yt, t += dyt;
        }
    }
}

The problem you may have had is the use of the comma operator in the macro. I recommend replacing the commas with ;, and putting the if parts inside {}, with line breaks. (Here I hand-inserted the { and }, then used M-x replace-string RET , RET ; C-Q C-J in Emacs, followed by C-M-\ to indent the region.)

    if (t + ry2*x <= crit1 ||
        t + rx2*y <= crit3) {

        x++;
        dxt += d2xt;
        t += dxt;

    } else if (t - rx2*y > crit2) {
        y--;
        dyt += d2yt;
        t += dyt;

    } else {
        x++;
        dxt += d2xt;
        t += dxt;

        y--;
        dyt += d2yt;
        t += dyt;
    }


Pretend the commas are semi-colons as that is effectively what they're being used for. The macros could have been written a little more straightforwardly like this:

#define incx() do { x++; dxt += d2xt; t += dxt; } while (0)
#define incy() do { y--; dyt += d2yt; t += dyt; } while (0)

Well, more straightforward in that the three statements are terminated by semi-colons. Less so with the use of the do { } while (0) loop, which is a common idiom for turning multiple statements into one big statement.

(Although it looks like a loop, it will only execute once and then end because the while (0) condition is guaranteed false. The purpose of this trick is that a semicolon is required after the macro so you use it just like a normal function: incx(); or incy();)

Anyways, the point of those macros is to take the repeated occurrences of x++; dxt += d2xt; t += dxt; and replace them with a single macro invocation. This sequence of three statements is repeated often enough to make this refactoring worthwhile.


In C, #defines are processed by the preprocessor, which does simple textual replacement before the compiler even sees the code. You have a source file like this:

#define incx() x++, dxt += d2xt, t += dxt 

if (t + ry2*x <= crit1 || t + rx2*y <= crit3)
    incx();

The preprocessor replaces every occurrence of incx() with x++, dxt += d2xt, t += dxt, so this results in:

if (t + ry2*x <= crit1 || t + rx2*y <= crit3)
    x++, dxt += d2xt, t += dxt;

This is what the compiler actually sees and tries to compile.


#define is evaluated by the preprocessor and simply replaces any instance of the first item with the rest of the line. So the code is equivalent to the following:

void ellipse(int xc, int yc, int rx, int ry, int color)
{
    int x = 0, y = ry;
    long rx2 = (long)rx*rx, ry2 = (long)ry*ry;
    long crit1 = -(rx2/4 + rx%2 + ry2);
    long crit2 = -(ry2/4 + ry%2 + rx2);
    long crit3 = -(ry2/4 + ry%2);
    long t = -rx2*y; // e(x+1/2,y-1/2) - (a^2+b^2)/4
    long dxt = 2*ry2*x, dyt = -2*rx2*y;
    long d2xt = 2*ry2, d2yt = 2*rx2;

    while (y>=0 && x<=rx)
    {
        pixel(xc+x, yc+y, color);
        if (x!=0 || y!=0)
            pixel(xc-x, yc-y, color);
        if (x!=0 && y!=0)
        {
            pixel(xc+x, yc-y, color);
            pixel(xc-x, yc+y, color);
        }
        if (t + ry2*x <= crit1 ||   //e(x+1,y-1/2) <= 0
            t + rx2*y <= crit3)     //e(x+1/2,y) <= 0
            x++, dxt += d2xt, t += dxt;
        else if (t - rx2*y > crit2) //e(x+1/2,y-1) > 0
            y--, dyt += d2yt, t += dyt;
        else
        {
            x++, dxt += d2xt, t += dxt;
            y--, dyt += d2yt, t += dyt;
        }
    }
}


It means the actual code has become too complex to read, and prior developers have resorted to using macros to make it more readable.

Since they didn't leave a comment - they failed


For a higher-level answer of "what's it doing", it's computing an approximate solution to a differential equation to draw the ellipse; the dxt, d2xt, dyt, and d2yt variables are rates-of-change (dx/dt, d^{2}x/dt^{2}, dy/dt, d^{2}y/dt^{2}, more or less). The incx() and incy() macros update all of the variables of the equation together by one step, to make sure that they stay in sync. Think of it as a very small attempt at information hiding.

0

精彩评论

暂无评论...
验证码 换一张
取 消