Макрос C ++, игнорирующий то, что после - PullRequest
0 голосов
/ 22 февраля 2020

Я работал над проблемой динамического программирования c и решил не использовать функцию std :: max, поскольку полагал, что макрос будет быстрее (без использования аргументов в стеке, без шаблонов).

Но он работает не совсем так, как ожидалось. Я выделил проблему, и она выглядит так:

#include <iostream>
#define maxi(a, b) (a <= b)? b : a

using namespace std;

int main()
{
    int a = 0, b = 0, c = 0;
    c =  maxi(a, b) + 1;
    cout << c;
    return 0;
}

Хотя это действительно возвращает максимум, похоже, после этого игнорируется добавление 1. В этом примере значение c заканчивается 0, в то время как я ожидаю, что оно равно 1. Почему это?

Ответы [ 4 ]

3 голосов
/ 22 февраля 2020

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

// ...
int a = 0, b = 0, c = 0;
c =  (a <= b)? b : a + 1;

Чтобы быстро исправить, просто поместите весь ваш макрос в дополнительный () как #define maxi(a, b) ((a <= b)? b : a). Это хорошая практика, когда вы пишете любой макрос. Это изменение приведет к следующему изменению в коде:

// ...
int a = 0, b = 0, c = 0;
c =  ((a <= b)? b : a) + 1;

Просто имейте в виду, что если ваши параметры a и b более сложные, вы столкнетесь с аналогичной проблемой, поэтому сделать макрос еще более ошибочным prone, вы должны поместить все параметры в отдельную () тоже, как в #define maxi(a, b) (((a) <= (b))? (b) : (a))

1 голос
/ 22 февраля 2020

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

    c =  (a <= b)? b : a + 1;

и, как вы можете видеть, вы вернете либо b, либо a+1. Это не то, что вы намеревались.

Вы должны написать макрос как

#define maxi(a, b) (((a) <= (b)) ? (b) : (a))

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

Это не в любом гораздо эффективнее, чем std::max. Компиляторы выполняют небольшие встроенные функции, и после вставки функция, использующая std::max, будет выглядеть почти так же, как если бы была подставлена ​​maxi. Не будет передачи аргументов функции, будь то в регистрах или в стеке.

Кстати. Функция является шаблонной или нет, не влияет на ее рабочие характеристики. Поэтому я не знаю, почему вы упоминаете об этом в вопросе.

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

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

maxi(f(a), f(b))

, где f - некоторая функция, будет заменять (примерно)

(f(a) <= f(b))? f(b) : f(a);

означает, что f всегда будет оцениваться три раза, для первых двух вызовов в сравнении и один раз для выбранной ветви.

С другой стороны std::max(f(a), f(b)) оценивает f только дважды .

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

0 голосов
/ 22 февраля 2020

Я работал над проблемой динамического программирования c и решил не использовать функцию std :: max, так как считал, что макрос будет быстрее (без аргументов в стеке, без шаблонов).

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


Чтобы увидеть, что не так с вашим макросом, скажите вашему компилятору, чтобы он показал вам предварительно обработанную версию вашего исходного кода (-E флаг для G CC):

Это:

#define maxi(a, b) (a <= b)? b : a

int main()
{
    int a = 0, b = 0, c = 0;
    c =  maxi(a, b) + 1;
}

Превращается в это:

int main()
{
    int a = 0, b = 0, c = 0;
    c = (a <= b)? b : a + 1;
}

Это не то, что вы хотели. Вот «Исправление»:

#define maxi(a, b) (((a) <= (b))? (b) : (a))

Это действительно не настоящее решение. Рассмотрим что-то вроде этого maxi(++a, b). Это расширяется до (((++a) <= (b))? (b) : (++a)), что потенциально увеличивает a в два раза. Это определенно не ожидаемое поведение.

0 голосов
/ 22 февраля 2020

Препроцессор C ++ заменяет слова перед компиляцией. Таким образом, ваша строка становится -

c = (a<=b) ? b : a +1;

, которая увеличивается a только при a>b

Для выполнения обоих кодов #define сегмент должен быть закручен фигурными скобками, чтобы убрать неоднозначность -

#define maxi(a, b) ((a <= b)? b : a)

Это сделает предварительно обработанную строку как

c = ((a<=b) ? b : a) +1;

, которая будет генерировать правильный вывод.

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