Что означает это определение? - PullRequest
0 голосов
/ 30 октября 2009

У меня есть этот код для рисования эллипса на экране, но я не понимаю, что означает оператор длинного определения, и я только хочу знать, как написать тот же код без всего этого запутанного оператора определения.

#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
            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();
        }
    }
}

Я пытался удалить определенный кусок за куском, и это не работает, какие-либо предложения?

Ответы [ 6 ]

3 голосов
/ 30 октября 2009

Представьте, что запятые - это точки с запятой, потому что это то, для чего они используются. Макросы могли бы быть написаны немного проще, например:

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

Что ж, более просто в том, что три утверждения заканчиваются точкой с запятой. Меньше так с использованием цикла do { } while (0), который является обычной идиомой для превращения нескольких операторов в один большой оператор.

(Хотя он выглядит как цикл, он будет выполняться только один раз, а затем завершится, потому что условие while (0) гарантировано ложно. Цель этого трюка состоит в том, что после макроса требуется точка с запятой, поэтому вы используете его точно так же нормальная функция: incx(); или incy();)

В любом случае, смысл этих макросов состоит в том, чтобы взять повторяющиеся вхождения x++; dxt += d2xt; t += dxt; и заменить их одним вызовом макроса. Эта последовательность из трех утверждений повторяется достаточно часто, чтобы сделать этот рефакторинг полезным.

3 голосов
/ 30 октября 2009

Если вы просто хотите удалить его, запустите код через cpp:

 cpp cpp.c > cppout.c

дает мне

# 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;
        }
    }
}

Возможно, у вас возникла проблема с использованием оператора запятой в макросе. Я рекомендую заменить запятые на ; и поместить части if внутри {} с переносом строки. (Здесь я вручную вставил {и}, затем использовал M-x replace-string RET , RET ; C-Q C-J в Emacs, а затем C-M-\ для отступа в регионе.)

    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;
    }
1 голос
/ 30 октября 2009

В C #define s обрабатываются препроцессором, который выполняет простую текстовую замену, прежде чем компилятор даже увидит код. У вас есть исходный файл, подобный этому:

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

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

Препроцессор заменяет каждое вхождение incx() на x++, dxt += d2xt, t += dxt, поэтому это приводит к:

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

Это то, что компилятор на самом деле видит и пытается компилировать.

0 голосов
/ 30 октября 2009

Для более высокого уровня ответа «что он делает» он вычисляет приближенное решение дифференциального уравнения для рисования эллипса; переменные dxt, d2xt, dyt и d2yt представляют собой скорости изменения (dx / dt, d ^ {2} x / dt ^ {2}, dy / dt, d ^ {2} y / dt ^ {2} , более менее). Макросы incx () и incy () обновляют все переменные уравнения за один шаг, чтобы обеспечить их синхронизацию. Думайте об этом как о очень маленькой попытке сокрытия информации.

0 голосов
/ 30 октября 2009

Это означает, что реальный код стал слишком сложным для чтения, и предыдущие разработчики прибегли к использованию макросов, чтобы сделать его более читабельным.

Так как они не оставили комментарий - они потерпели неудачу

0 голосов
/ 30 октября 2009

#define оценивается препроцессором и просто заменяет любой экземпляр первого элемента остальной частью строки. Таким образом, код эквивалентен следующему:

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;
        }
    }
}
...