Использование макроса приводит к неправильному выводу при использовании в качестве части большего математического выражения - почему это происходит? - PullRequest
6 голосов
/ 22 января 2010

Это обычная программа на С, которую я обнаружил в каком-то банке вопросов. Это показано ниже:

#define CUBE(p) p*p*p

main()
{
    int k;
    k = 27 / CUBE(3);
    printf("%d", k);
}

Согласно моему пониманию и знанию, значение K должно быть 1, поскольку CUBE (3) будет заменен на 3 * 3 * 3 во время предварительной обработки, и после последующей компиляции он будет давать значение 1, но вместо этого он имеет показал значение 81, что заставило меня любопытно узнать, как это произошло.

Может ли кто-нибудь обосновать ответ 81 на этот вопрос выше.

Ответы [ 13 ]

15 голосов
/ 22 января 2010

Препроцессор просто заменяет

CUBE(3)

с

3*3*3

Итак, вы получите:

k=27/3*3*3

Что, если считать слева направо с приоритетом оператора, в действительности равно 81.

Если вы добавите скобки вокруг макроса, вы должны найти правильные результаты:

#define CUBE(p) (p*p*p)

Было бы еще лучше окружить каждый экземпляр p круглыми скобками, например:

#define CUBE(p) ((p)*(p)*(p))

Что позволит вам корректно передавать выражения в макрос (например, 1 + 2).

4 голосов
/ 22 января 2010

Из-за приоритета оператора 27/3*3*3 = 81

Вы можете использовать вместо:

inline int cube(int p) { return p*p*p; }
3 голосов
/ 22 января 2010

Препроцессоры должны быть в скобках правильно. Замените его на

#define CUBE(p) ((p)*(p)*(p))

и см.

2 голосов
/ 22 января 2010

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

k = 27 / 3 * 3 * 3;

Поскольку умножение и деление происходят слева направо, получается:

k = ((27 / 3) * 3) * 3;

Итак, вы хотите изменить это двумя способами:

#define CUBE(p) ((p)*(p)*(p))

Внешние скобки приводят к умножению перед любыми другими операциями.

Скобки вокруг отдельных p относятся к случаю, когда вы делаете:

CUBE(1 + 2);

Без этих внутренних скобок приоритет оператора может сбить вас с толку.

2 голосов
/ 22 января 2010

C макросы выполняют текстовую подстановку (т. Е. Это эквивалентно копированию и вставке кода). Итак, ваш код идет от:

k=27/CUBE(3);

до

k=27/3*3*3;

Деление и умножение имеют одинаковый приоритет и имеют ассоциативность слева направо, поэтому это анализируется как:

k=((27/3)*3)*3;

, что составляет 9 * 3 * 3 = 81.

Именно поэтому макросы C всегда должны определяться с использованием свободных скобок:

#define CUBE(p) ((p) * (p) * (p))

Для получения дополнительной информации см. http://c -faq.com / cpp / safemacros.html в FAQ по comp.lang.c.

1 голос
/ 22 января 2010

Ваш макрос не защищен. Попробуйте

#define CUBE(p) ((p)*(p)*(p))

Текущий макрос был расширен до

k=27/3*3*3

, что ((27/3) * 3) * 3

0 голосов
/ 01 февраля 2010

Привет ответ для этого: 81 Объяснение: На этапе k = 27 / куб (3) куб (3) заменяется препроцессором на 3 * 3 * 3 в этом выражении 27/3 оценивается компилятором c (приоритет оператора) результат (27/3): 9 утверждение k = 27/3 * 3 * 3 становится как k = 9 * 3 * 3; результат для вышеупомянутого утверждения - 81:

0 голосов
/ 22 января 2010

это способ, которым реализуется ассоциативность и приоритет операторов. когда выражение расширяется, оно становится 27/3 * 3 * 3, а не 27 / (3 * 3 * 3) теперь деление и умножение имеют одинаковый приоритет в C, но ассоциативность слева направо для обоих. так что это может быть показано как: (27/3) * 3 * 3, что в свою очередь равно (9 * 3) * 3 = 81 Кроме того, если вы помните старое арифметическое правило BODMAS (Вычитание с умножением с делением в скобках) , это порядок старшинства, затем мы сначала делим деление, а затем умножаем. поэтому мы снова получаем ответ 81 для 27/3 * 3 * 3.

0 голосов
/ 22 января 2010

Оба оператора / и * имеют одинаковый приоритет. Чтобы сначала выполнить 3 * 3 * 3, нужно заключить их в скобки.

#include <stdio.h>

#define CUBE(p) p*p*p

int
main ()
{
  int k;
  k=27/(CUBE(3));
  printf("%d",k);
  return 0;
}
0 голосов
/ 22 января 2010

27/3 * 3 * 3 = 9 * 3 * 3 = 81?

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