Проблема с макросами - PullRequest
       15

Проблема с макросами

5 голосов
/ 29 августа 2009

HI,

Может ли кто-нибудь помочь мне понять, почему значение КВАДРАТА (x) равно 49?

Я использую Visual C ++ 6.0.

#define SQUARE(X) X * X

int main(int argc, char* argv[])
{
    int y = 5;

    printf("%d\n",SQUARE(++y));
    return 0;
}

Ответы [ 4 ]

16 голосов
/ 29 августа 2009

Нил Баттерворт, Марк и Павел правы.

SQUARE (++ y) расширяется до ++ y * ++ y, что увеличивает значение y в два раза.

Другая проблема, с которой вы можете столкнуться: КВАДРАТ (a + b) расширяется до a + b * a + b, который не является (a + b) * (a + b), но a + (b * a) + b. Вы должны позаботиться о добавлении скобок вокруг элементов, когда это необходимо при определении макросов: #define SQUARE (X) ((X) * (X)) немного менее рискованно. (Ян Кемп написал это первым в своем комментарии)

Вместо этого вы можете использовать встроенную функцию шаблона (не менее эффективную во время выполнения), например, такую:

template <class T>
inline T square(T value)
{
    return value*value;
}

Вы можете проверить это работает:

int i = 2;
std::cout << square(++i) << " should be 9" << std::endl;
std::cout << square(++i) << " should be 16" << std::endl;

(не нужно писать

square<int>(++i)

потому что тип int неявный для i)

15 голосов
/ 29 августа 2009

Поскольку макрос расширяется до:

++y * ++y

, который дает неопределенное поведение в C ++ - результат может будь что угодно. Эта очень известная проблема должна быть рассмотрена в любом приличном учебнике, который описывает использование макросов Какой из них вы используете?

5 голосов
/ 29 августа 2009

Макросы не являются функциями: они просто изменяют текст программы. Эта операция называется preprocessing и выполняется автоматически до компиляции вашего кода. Люди пишут макросы, чтобы сэкономить свое время и внести некоторую изменчивость в свой исходный код.

Когда вы пишете SQUARE(x), никакого фактического вызова функции не происходит, только текст изменяется. Операция довольно тупая, поэтому вы должны предпринять дополнительные меры предосторожности в таких случаях, как ваш. Обратитесь к другим ответам для объяснения вашего случая.

5 голосов
/ 29 августа 2009

Поскольку макросы выполняют текстовую подстановку, код, который вы написали, расширяется до

printf("%d\n",++y * ++y );

, а затем порядок операций - неопределенное поведение, так что компилятор видит 2 приращения и затем умножение

Так что будьте осторожны с макросами, чтобы лучше использовать функции, которые, поскольку компилятор может расширяться внутри строки, больше не будут запускаться.

Во-вторых, не предполагайте, что произойдет, если вы увеличите и используете переменные

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...